Commit b30f05db by Bernd Schmidt Committed by Bernd Schmidt

Combined compare & jump infrastructure

From-SVN: r28752
parent 9bb21998
Wed Aug 18 18:20:40 1999 Bernd Schmidt <bernds@cygnus.co.uk>
* expmed.c (emit_store_flag): If UNSIGNEDP, call unsigned_condition
on CODE.
(emit_store_flag_force): Use do_compare_rtx_and_jump.
(do_cmp_and_jump): Formatting fixes.
* expr.c (do_compare_and_jump): Renamed from compare; changed to call
do_compare_rtx_and_jump instead of compare_from_rtx.
(do_compare_rtx_and_jump): New function; mostly copied from
compare_from_rtx.
(do_jump_for_compare): Delete.
(expand_expr): Use do_compare_rtx_and_jump when handling MAX_EXPR and
MIN_EXPR.
(do_jump): Use do_compare_and_jump or do_compare_rtx_and_jump instead
of compare/do_jump_for_compare pairs.
(do_jump_by_parts_greater): Use do_jump_by_parts_greater_rtx.
(do_jump_by_parts_greater_rtx): Use do_compare_rtx_and_jump instead of
compare_from_rtx/do_jump_for_compare pairs.
(do_jump_by_parts_equality): Likewise.
(do_jump_by_parts_equality_rtx): Likewise.
* expr.h (do_compare_rtx_and_jump): Declare.
* optabs.c (prepare_cmp_insn): New function, contains most of the code
that used to be in emit_cmp_insn.
(cmp_available_p): New function.
(prepare_operand): New function.
(emit_cmp_and_jump_insn_1): New function, contains some code that used
to be in emit_cmp_insn.
(prepare_float_lib_cmp): Renamed from emit_float_lib_cmp; change some
parameters to be pointers; don't emit final compare but modify some of
the values pointed to by the args so the caller can perform the
correct comparison.
(expand_binop): Call emit_store_flag_force with signed forms of
comparison code.
(expand_abs): Use do_compare_rtx_and_jump instead of compare_from_rtx/
emit_jump_insn pair.
(emit_cmp_and_jump_insn): Use prepare_cmp_insn and
emit_cmp_and_jump_insn_1. Call emit_queue.
(emit_cmp_insn): Just call emit_cmp_and_jump_insns with zero for LABEL
arg.
* flow.c (tidy_fallthru_edge): If HAVE_cc0, verify insn before a
jump sets cc0 before deleting it.
* integrate.c (expand_inline_function): Likewise.
* unroll.c (unroll_loop): Similar changes in several places.
(copy_loop_body): If HAVE_cc0, verify insn before a jump sets cc0
before deleting it.
Wed Aug 18 06:37:44 1999 Bernd Schmidt <bernds@cygnus.co.uk> Wed Aug 18 06:37:44 1999 Bernd Schmidt <bernds@cygnus.co.uk>
* Makefile.in (insn-recog.o): Update dependencies. * Makefile.in (insn-recog.o): Update dependencies.
......
...@@ -4093,6 +4093,9 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) ...@@ -4093,6 +4093,9 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
rtx last = get_last_insn (); rtx last = get_last_insn ();
rtx pattern, comparison; rtx pattern, comparison;
if (unsignedp)
code = unsigned_condition (code);
/* If one operand is constant, make it the second one. Only do this /* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */ if the other operand is not constant as well. */
...@@ -4492,15 +4495,10 @@ emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep) ...@@ -4492,15 +4495,10 @@ emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
target = gen_reg_rtx (GET_MODE (target)); target = gen_reg_rtx (GET_MODE (target));
emit_move_insn (target, const1_rtx); emit_move_insn (target, const1_rtx);
tem = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0);
if (GET_CODE (tem) == CONST_INT)
return tem;
label = gen_label_rtx (); label = gen_label_rtx ();
if (bcc_gen_fctn[(int) code] == 0) do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX, 0,
abort (); NULL_RTX, label);
emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
emit_move_insn (target, const0_rtx); emit_move_insn (target, const0_rtx);
emit_label (label); emit_label (label);
...@@ -4525,7 +4523,7 @@ do_cmp_and_jump (arg1, arg2, op, mode, label) ...@@ -4525,7 +4523,7 @@ do_cmp_and_jump (arg1, arg2, op, mode, label)
/* If this mode is an integer too wide to compare properly, /* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */ 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))
{ {
rtx label2 = gen_label_rtx (); rtx label2 = gen_label_rtx ();
......
...@@ -152,8 +152,7 @@ static rtx expand_increment PROTO((tree, int, int)); ...@@ -152,8 +152,7 @@ static rtx expand_increment PROTO((tree, int, int));
static void preexpand_calls PROTO((tree)); static void preexpand_calls PROTO((tree));
static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx)); static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
static void do_jump_by_parts_equality PROTO((tree, rtx, rtx)); static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
static void do_jump_for_compare PROTO((rtx, rtx, rtx)); static void do_compare_and_jump PROTO((tree, enum rtx_code, enum rtx_code, rtx, rtx));
static rtx compare PROTO((tree, enum rtx_code, enum rtx_code));
static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int)); static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int));
/* Record for each mode whether we can move a register directly to or /* Record for each mode whether we can move a register directly to or
...@@ -7297,7 +7296,7 @@ expand_expr (exp, target, tmode, modifier) ...@@ -7297,7 +7296,7 @@ expand_expr (exp, target, tmode, modifier)
/* If this mode is an integer too wide to compare properly, /* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */ 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))
{ {
if (code == MAX_EXPR) if (code == MAX_EXPR)
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type), do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
...@@ -7305,29 +7304,15 @@ expand_expr (exp, target, tmode, modifier) ...@@ -7305,29 +7304,15 @@ expand_expr (exp, target, tmode, modifier)
else else
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type), do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
op1, target, NULL_RTX, op0); op1, target, NULL_RTX, op0);
emit_move_insn (target, op1);
} }
else else
{ {
if (code == MAX_EXPR) int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))) do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
? compare_from_rtx (target, op1, GEU, 1, mode, NULL_RTX, 0) unsignedp, mode, NULL_RTX, 0, NULL_RTX,
: compare_from_rtx (target, op1, GE, 0, mode, NULL_RTX, 0)); op0);
else
temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
? compare_from_rtx (target, op1, LEU, 1, mode, NULL_RTX, 0)
: compare_from_rtx (target, op1, LE, 0, mode, NULL_RTX, 0));
if (temp == const0_rtx)
emit_move_insn (target, op1);
else if (temp != const_true_rtx)
{
if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op0));
else
abort ();
emit_move_insn (target, op1);
}
} }
emit_move_insn (target, op1);
emit_label (op0); emit_label (op0);
return target; return target;
...@@ -8626,7 +8611,6 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8626,7 +8611,6 @@ do_jump (exp, if_false_label, if_true_label)
These cases set DROP_THROUGH_LABEL nonzero. */ These cases set DROP_THROUGH_LABEL nonzero. */
rtx drop_through_label = 0; rtx drop_through_label = 0;
rtx temp; rtx temp;
rtx comparison = 0;
int i; int i;
tree type; tree type;
enum machine_mode mode; enum machine_mode mode;
...@@ -8692,10 +8676,10 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8692,10 +8676,10 @@ do_jump (exp, if_false_label, if_true_label)
case MINUS_EXPR: case MINUS_EXPR:
/* Non-zero iff operands of minus differ. */ /* Non-zero iff operands of minus differ. */
comparison = compare (build (NE_EXPR, TREE_TYPE (exp), do_compare_and_jump (build (NE_EXPR, TREE_TYPE (exp),
TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 0),
TREE_OPERAND (exp, 1)), TREE_OPERAND (exp, 1)),
NE, NE); NE, NE, if_false_label, if_true_label);
break; break;
case BIT_AND_EXPR: case BIT_AND_EXPR:
...@@ -8854,7 +8838,7 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8854,7 +8838,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (inner_type))) && !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_false_label, if_true_label); do_jump_by_parts_equality (exp, if_false_label, if_true_label);
else else
comparison = compare (exp, EQ, EQ); do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
break; break;
} }
...@@ -8894,7 +8878,7 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8894,7 +8878,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (inner_type))) && !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_true_label, if_false_label); do_jump_by_parts_equality (exp, if_true_label, if_false_label);
else else
comparison = compare (exp, NE, NE); do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
break; break;
} }
...@@ -8904,7 +8888,7 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8904,7 +8888,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label); do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
else else
comparison = compare (exp, LT, LTU); do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
break; break;
case LE_EXPR: case LE_EXPR:
...@@ -8913,7 +8897,7 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8913,7 +8897,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label); do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
else else
comparison = compare (exp, LE, LEU); do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
break; break;
case GT_EXPR: case GT_EXPR:
...@@ -8922,7 +8906,7 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8922,7 +8906,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label); do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
else else
comparison = compare (exp, GT, GTU); do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
break; break;
case GE_EXPR: case GE_EXPR:
...@@ -8931,7 +8915,7 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8931,7 +8915,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label); do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
else else
comparison = compare (exp, GE, GEU); do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
break; break;
default: default:
...@@ -8947,42 +8931,28 @@ do_jump (exp, if_false_label, if_true_label) ...@@ -8947,42 +8931,28 @@ do_jump (exp, if_false_label, if_true_label)
temp = copy_to_reg (temp); temp = copy_to_reg (temp);
#endif #endif
do_pending_stack_adjust (); do_pending_stack_adjust ();
if (GET_CODE (temp) == CONST_INT) /* Do any postincrements in the expression that was tested. */
comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx); emit_queue ();
else if (GET_CODE (temp) == LABEL_REF)
comparison = const_true_rtx; if (GET_CODE (temp) == CONST_INT || GET_CODE (temp) == LABEL_REF)
{
rtx target = temp == const0_rtx ? if_false_label : if_true_label;
if (target)
emit_jump (target);
}
else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
&& !can_compare_p (GET_MODE (temp))) && ! can_compare_p (GET_MODE (temp)))
/* Note swapping the labels gives us not-equal. */ /* Note swapping the labels gives us not-equal. */
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label); do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
else if (GET_MODE (temp) != VOIDmode) else if (GET_MODE (temp) != VOIDmode)
comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)), do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
NE, TREE_UNSIGNED (TREE_TYPE (exp)), NE, TREE_UNSIGNED (TREE_TYPE (exp)),
GET_MODE (temp), NULL_RTX, 0); GET_MODE (temp), NULL_RTX, 0,
if_false_label, if_true_label);
else else
abort (); abort ();
} }
/* Do any postincrements in the expression that was tested. */
emit_queue ();
/* If COMPARISON is nonzero here, it is an rtx that can be substituted
straight into a conditional jump instruction as the jump condition.
Otherwise, all the work has been done already. */
if (comparison == const_true_rtx)
{
if (if_true_label)
emit_jump (if_true_label);
}
else if (comparison == const0_rtx)
{
if (if_false_label)
emit_jump (if_false_label);
}
else if (comparison)
do_jump_for_compare (comparison, if_false_label, if_true_label);
if (drop_through_label) if (drop_through_label)
{ {
/* If do_jump produces code that might be jumped around, /* If do_jump produces code that might be jumped around,
...@@ -9007,57 +8977,9 @@ do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label) ...@@ -9007,57 +8977,9 @@ do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0); rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0);
rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0); rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))); enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
rtx drop_through_label = 0;
int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))); int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
int i;
if (! if_true_label || ! if_false_label)
drop_through_label = gen_label_rtx ();
if (! if_true_label)
if_true_label = drop_through_label;
if (! if_false_label)
if_false_label = drop_through_label;
/* Compare a word at a time, high order first. */
for (i = 0; i < nwords; i++)
{
rtx comp;
rtx op0_word, op1_word;
if (WORDS_BIG_ENDIAN)
{
op0_word = operand_subword_force (op0, i, mode);
op1_word = operand_subword_force (op1, i, mode);
}
else
{
op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
}
/* All but high-order word must be compared as unsigned. */ do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label);
comp = compare_from_rtx (op0_word, op1_word,
(unsignedp || i > 0) ? GTU : GT,
unsignedp, word_mode, NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_true_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, NULL_RTX, if_true_label);
/* Consider lower words only if these are equal. */
comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, NULL_RTX, if_false_label);
}
if (if_false_label)
emit_jump (if_false_label);
if (drop_through_label)
emit_label (drop_through_label);
} }
/* Compare OP0 with OP1, word at a time, in mode MODE. /* Compare OP0 with OP1, word at a time, in mode MODE.
...@@ -9100,21 +9022,13 @@ do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true ...@@ -9100,21 +9022,13 @@ do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true
} }
/* All but high-order word must be compared as unsigned. */ /* All but high-order word must be compared as unsigned. */
comp = compare_from_rtx (op0_word, op1_word, do_compare_rtx_and_jump (op0_word, op1_word, GT,
(unsignedp || i > 0) ? GTU : GT, (unsignedp || i > 0), word_mode, NULL_RTX, 0,
unsignedp, word_mode, NULL_RTX, 0); NULL_RTX, if_true_label);
if (comp == const_true_rtx)
emit_jump (if_true_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, NULL_RTX, if_true_label);
/* Consider lower words only if these are equal. */ /* Consider lower words only if these are equal. */
comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode, do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, 0); NULL_RTX, 0, NULL_RTX, if_false_label);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, NULL_RTX, if_false_label);
} }
if (if_false_label) if (if_false_label)
...@@ -9142,16 +9056,11 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label) ...@@ -9142,16 +9056,11 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label)
drop_through_label = if_false_label = gen_label_rtx (); drop_through_label = if_false_label = gen_label_rtx ();
for (i = 0; i < nwords; i++) for (i = 0; i < nwords; i++)
{ do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode),
operand_subword_force (op1, i, mode), operand_subword_force (op1, i, mode),
EQ, TREE_UNSIGNED (TREE_TYPE (exp)), EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
word_mode, NULL_RTX, 0); word_mode, NULL_RTX, 0, if_false_label,
if (comp == const_true_rtx) NULL_RTX);
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, if_false_label, NULL_RTX);
}
if (if_true_label) if (if_true_label)
emit_jump (if_true_label); emit_jump (if_true_label);
...@@ -9187,15 +9096,8 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) ...@@ -9187,15 +9096,8 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
if (part != 0) if (part != 0)
{ {
rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode, do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
NULL_RTX, 0); NULL_RTX, 0, if_false_label, if_true_label);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp == const0_rtx)
emit_jump (if_true_label);
else
do_jump_for_compare (comp, if_false_label, if_true_label);
return; return;
} }
...@@ -9205,15 +9107,9 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) ...@@ -9205,15 +9107,9 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
drop_through_label = if_false_label = gen_label_rtx (); drop_through_label = if_false_label = gen_label_rtx ();
for (i = 0; i < nwords; i++) for (i = 0; i < nwords; i++)
{ do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
rtx comp = compare_from_rtx (operand_subword_force (op0, i, const0_rtx, EQ, 1, word_mode, NULL_RTX, 0,
GET_MODE (op0)), if_false_label, NULL_RTX);
const0_rtx, EQ, 1, word_mode, NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, if_false_label, NULL_RTX);
}
if (if_true_label) if (if_true_label)
emit_jump (if_true_label); emit_jump (if_true_label);
...@@ -9222,167 +9118,83 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) ...@@ -9222,167 +9118,83 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
emit_label (drop_through_label); emit_label (drop_through_label);
} }
/* Given a comparison expression in rtl form, output conditional branches to /* Generate code for a comparison of OP0 and OP1 with rtx code CODE.
IF_TRUE_LABEL, IF_FALSE_LABEL, or both. */ (including code to compute the values to be compared)
and set (CC0) according to the result.
static void The decision as to signed or unsigned comparison must be made by the caller.
do_jump_for_compare (comparison, if_false_label, if_true_label)
rtx comparison, if_false_label, if_true_label;
{
if (if_true_label)
{
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
(if_true_label));
else
abort ();
if (if_false_label)
emit_jump (if_false_label);
}
else if (if_false_label)
{
rtx first = get_last_insn (), insn, branch;
int br_count;
/* Output the branch with the opposite condition. Then try to invert
what is generated. If more than one insn is a branch, or if the
branch is not the last insn written, abort. If we can't invert
the branch, emit make a true label, redirect this jump to that,
emit a jump to the false label and define the true label. */
/* ??? Note that we wouldn't have to do any of this nonsense if
we passed both labels into a combined compare-and-branch.
Ah well, jump threading does a good job of repairing the damage. */
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
(if_false_label));
else
abort ();
/* Here we get the first insn that was just emitted. It used to be the We force a stack adjustment unless there are currently
case that, on some machines, emitting the branch would discard things pushed on the stack that aren't yet used.
the previous compare insn and emit a replacement. This isn't
done anymore, but abort if we see that FIRST is deleted. */
if (first == 0) If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
first = get_insns (); compared.
else if (INSN_DELETED_P (first))
abort ();
else
first = NEXT_INSN (first);
/* Look for multiple branches in this sequence, as might be generated If ALIGN is non-zero, it is the alignment of this type; if zero, the
for a multi-word integer comparison. */ size of MODE should be used. */
br_count = 0; rtx
branch = NULL_RTX; compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
for (insn = first; insn ; insn = NEXT_INSN (insn)) register rtx op0, op1;
if (GET_CODE (insn) == JUMP_INSN) enum rtx_code code;
{ int unsignedp;
branch = insn; enum machine_mode mode;
br_count += 1; rtx size;
} int align;
{
rtx tem;
/* If we've got one branch at the end of the sequence, /* If one operand is constant, make it the second one. Only do this
we can try to reverse it. */ if the other operand is not constant as well. */
if (br_count == 1 && NEXT_INSN (branch) == NULL_RTX) if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
|| (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
{ {
rtx insn_label; tem = op0;
insn_label = XEXP (condjump_label (branch), 0); op0 = op1;
JUMP_LABEL (branch) = insn_label; op1 = tem;
code = swap_condition (code);
if (insn_label != if_false_label)
abort ();
if (invert_jump (branch, if_false_label))
return;
} }
/* Multiple branches, or reversion failed. Convert to branches if (flag_force_mem)
around an unconditional jump. */
if_true_label = gen_label_rtx ();
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{ {
rtx insn_label; op0 = force_not_mem (op0);
insn_label = XEXP (condjump_label (insn), 0); op1 = force_not_mem (op1);
JUMP_LABEL (insn) = insn_label;
if (insn_label == if_false_label)
redirect_jump (insn, if_true_label);
}
emit_jump (if_false_label);
emit_label (if_true_label);
} }
}
/* Generate code for a comparison expression EXP
(including code to compute the values to be compared)
and set (CC0) according to the result.
SIGNED_CODE should be the rtx operation for this comparison for
signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
We force a stack adjustment unless there are currently
things pushed on the stack that aren't yet used. */
static rtx
compare (exp, signed_code, unsigned_code)
register tree exp;
enum rtx_code signed_code, unsigned_code;
{
register rtx op0, op1;
register tree type;
register enum machine_mode mode;
int unsignedp;
enum rtx_code code;
/* Don't crash if the comparison was erroneous. */
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
return op0;
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0); do_pending_stack_adjust ();
type = TREE_TYPE (TREE_OPERAND (exp, 0));
mode = TYPE_MODE (type);
unsignedp = TREE_UNSIGNED (type);
code = unsignedp ? unsigned_code : signed_code;
#ifdef HAVE_canonicalize_funcptr_for_compare if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
/* If function pointers need to be "canonicalized" before they can && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
be reliably compared, then canonicalize them. */ return tem;
if (HAVE_canonicalize_funcptr_for_compare
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== FUNCTION_TYPE))
{
rtx new_op0 = gen_reg_rtx (mode);
emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0)); #if 0
op0 = new_op0; /* There's no need to do this now that combine.c can eliminate lots of
} sign extensions. This can be less efficient in certain cases on other
machines. */
if (HAVE_canonicalize_funcptr_for_compare /* If this is a signed equality comparison, we can do it as an
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE unsigned comparison since zero-extension is cheaper than sign
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1)))) extension and comparisons with zero are done as unsigned. This is
== FUNCTION_TYPE)) the case even on machines that can do fast sign extension, since
zero-extension is easier to combine with other operations than
sign-extension is. If we are comparing against a constant, we must
convert it to what it would look like unsigned. */
if ((code == EQ || code == NE) && ! unsignedp
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
{ {
rtx new_op1 = gen_reg_rtx (mode); if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1)); op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
op1 = new_op1; unsignedp = 1;
} }
#endif #endif
return compare_from_rtx (op0, op1, code, unsignedp, mode, emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
((mode == BLKmode)
? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX), return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
} }
/* Like compare but expects the values to compare as two rtx's. /* Like do_compare_and_jump but expects the values to compare as two rtx's.
The decision as to signed or unsigned comparison must be made by the caller. The decision as to signed or unsigned comparison must be made by the caller.
If MODE is BLKmode, SIZE is an RTX giving the size of the objects being If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
...@@ -9391,16 +9203,28 @@ compare (exp, signed_code, unsigned_code) ...@@ -9391,16 +9203,28 @@ compare (exp, signed_code, unsigned_code)
If ALIGN is non-zero, it is the alignment of this type; if zero, the If ALIGN is non-zero, it is the alignment of this type; if zero, the
size of MODE should be used. */ size of MODE should be used. */
rtx void
compare_from_rtx (op0, op1, code, unsignedp, mode, size, align) do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
if_false_label, if_true_label)
register rtx op0, op1; register rtx op0, op1;
enum rtx_code code; enum rtx_code code;
int unsignedp; int unsignedp;
enum machine_mode mode; enum machine_mode mode;
rtx size; rtx size;
int align; int align;
rtx if_false_label, if_true_label;
{ {
rtx tem; rtx tem;
int dummy_true_label = 0;
/* Reverse the comparison if that is safe and we want to jump if it is
false. */
if (! if_true_label && ! FLOAT_MODE_P (mode))
{
if_true_label = if_false_label;
if_false_label = 0;
code = reverse_condition (code);
}
/* If one operand is constant, make it the second one. Only do this /* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */ if the other operand is not constant as well. */
...@@ -9424,7 +9248,19 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align) ...@@ -9424,7 +9248,19 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
&& (tem = simplify_relational_operation (code, mode, op0, op1)) != 0) && (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
return tem; {
if (tem == const_true_rtx)
{
if (if_true_label)
emit_jump (if_true_label);
}
else
{
if (if_false_label)
emit_jump (if_false_label);
}
return;
}
#if 0 #if 0
/* There's no need to do this now that combine.c can eliminate lots of /* There's no need to do this now that combine.c can eliminate lots of
...@@ -9448,9 +9284,89 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align) ...@@ -9448,9 +9284,89 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
} }
#endif #endif
emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align); if (! if_true_label)
{
dummy_true_label = 1;
if_true_label = gen_label_rtx ();
}
return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp, align,
if_true_label);
if (if_false_label)
emit_jump (if_false_label);
if (dummy_true_label)
emit_label (if_true_label);
}
/* Generate code for a comparison expression EXP (including code to compute
the values to be compared) and a conditional jump to IF_FALSE_LABEL and/or
IF_TRUE_LABEL. One of the labels can be NULL_RTX, in which case the
generated code will drop through.
SIGNED_CODE should be the rtx operation for this comparison for
signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
We force a stack adjustment unless there are currently
things pushed on the stack that aren't yet used. */
static void
do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
if_true_label)
register tree exp;
enum rtx_code signed_code, unsigned_code;
rtx if_false_label, if_true_label;
{
register rtx op0, op1;
register tree type;
register enum machine_mode mode;
int unsignedp;
enum rtx_code code;
/* Don't crash if the comparison was erroneous. */
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
return;
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
type = TREE_TYPE (TREE_OPERAND (exp, 0));
mode = TYPE_MODE (type);
unsignedp = TREE_UNSIGNED (type);
code = unsignedp ? unsigned_code : signed_code;
#ifdef HAVE_canonicalize_funcptr_for_compare
/* If function pointers need to be "canonicalized" before they can
be reliably compared, then canonicalize them. */
if (HAVE_canonicalize_funcptr_for_compare
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== FUNCTION_TYPE))
{
rtx new_op0 = gen_reg_rtx (mode);
emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
op0 = new_op0;
}
if (HAVE_canonicalize_funcptr_for_compare
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
== FUNCTION_TYPE))
{
rtx new_op1 = gen_reg_rtx (mode);
emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
op1 = new_op1;
}
#endif
/* Do any postincrements in the expression that was tested. */
emit_queue ();
do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
((mode == BLKmode)
? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,
if_false_label, if_true_label);
} }
/* Generate code to calculate EXP using a store-flag instruction /* Generate code to calculate EXP using a store-flag instruction
......
...@@ -801,6 +801,9 @@ extern void do_jump PROTO((tree, rtx, rtx)); ...@@ -801,6 +801,9 @@ extern void do_jump PROTO((tree, rtx, rtx));
/* Generate rtl to compare two rtx's, will call emit_cmp_insn. */ /* Generate rtl to compare two rtx's, will call emit_cmp_insn. */
extern rtx compare_from_rtx PROTO((rtx, rtx, enum rtx_code, int, extern rtx compare_from_rtx PROTO((rtx, rtx, enum rtx_code, int,
enum machine_mode, rtx, int)); enum machine_mode, rtx, int));
extern void do_compare_rtx_and_jump PROTO((rtx, rtx, enum rtx_code, int,
enum machine_mode, rtx, int,
rtx, rtx));
/* Generate a tablejump instruction (used for switch statements). */ /* Generate a tablejump instruction (used for switch statements). */
extern void do_tablejump PROTO((rtx, enum machine_mode, rtx, rtx, rtx)); extern void do_tablejump PROTO((rtx, enum machine_mode, rtx, rtx, rtx));
......
...@@ -1998,7 +1998,7 @@ tidy_fallthru_edge (e, b, c) ...@@ -1998,7 +1998,7 @@ tidy_fallthru_edge (e, b, c)
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* If this was a conditional jump, we need to also delete /* If this was a conditional jump, we need to also delete
the insn that set cc0. */ the insn that set cc0. */
if (! simplejump_p (q) && condjump_p (q)) if (! simplejump_p (q) && condjump_p (q) && sets_cc0_p (PREV_INSN (q)))
q = PREV_INSN (q); q = PREV_INSN (q);
#endif #endif
......
...@@ -1958,7 +1958,8 @@ expand_inline_function (fndecl, parms, target, ignore, type, ...@@ -1958,7 +1958,8 @@ expand_inline_function (fndecl, parms, target, ignore, type,
if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value) if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value)
{ {
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* The previous insn set cc0 for us. So delete it. */ /* If the previous insn set cc0 for us, delete it. */
if (sets_cc0_p (PREV_INSN (copy)))
delete_insn (PREV_INSN (copy)); delete_insn (PREV_INSN (copy));
#endif #endif
......
...@@ -267,6 +267,15 @@ static void init_floating_libfuncs PROTO((optab, const char *, int)); ...@@ -267,6 +267,15 @@ static void init_floating_libfuncs PROTO((optab, const char *, int));
#ifdef HAVE_conditional_trap #ifdef HAVE_conditional_trap
static void init_traps PROTO((void)); static void init_traps PROTO((void));
#endif #endif
static int cmp_available_p PROTO((enum machine_mode, enum rtx_code, 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 *));
/* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to /* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to
the result of operation CODE applied to OP0 (and OP1 if it is a binary the result of operation CODE applied to OP0 (and OP1 if it is a binary
...@@ -1326,7 +1335,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) ...@@ -1326,7 +1335,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
carry_out = gen_reg_rtx (word_mode); carry_out = gen_reg_rtx (word_mode);
carry_out = emit_store_flag_force (carry_out, carry_out = emit_store_flag_force (carry_out,
(binoptab == add_optab (binoptab == add_optab
? LTU : GTU), ? LT : GT),
x, op0_piece, x, op0_piece,
word_mode, 1, normalizep); word_mode, 1, normalizep);
} }
...@@ -1349,7 +1358,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) ...@@ -1349,7 +1358,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* Get out carry from adding/subtracting carry in. */ /* Get out carry from adding/subtracting carry in. */
carry_tmp = emit_store_flag_force (carry_tmp, carry_tmp = emit_store_flag_force (carry_tmp,
binoptab == add_optab binoptab == add_optab
? LTU : GTU, ? LT : GT,
x, carry_in, x, carry_in,
word_mode, 1, normalizep); word_mode, 1, normalizep);
...@@ -2463,19 +2472,8 @@ expand_abs (mode, op0, target, safe) ...@@ -2463,19 +2472,8 @@ expand_abs (mode, op0, target, safe)
do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
NULL_RTX, op1); NULL_RTX, op1);
else else
{ do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode, NULL_RTX, 0, NULL_RTX, op1);
NULL_RTX, 0);
if (temp == const1_rtx)
return target;
else if (temp != const0_rtx)
{
if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
else
abort ();
}
}
op0 = expand_unop (mode, neg_optab, target, target, 0); op0 = expand_unop (mode, neg_optab, target, target, 0);
if (op0 != target) if (op0 != target)
...@@ -2983,31 +2981,57 @@ emit_0_to_1_insn (x) ...@@ -2983,31 +2981,57 @@ emit_0_to_1_insn (x)
emit_move_insn (x, const1_rtx); emit_move_insn (x, const1_rtx);
} }
/* Generate code to compare X with Y /* Nonzero if we can perform a comparison of mode MODE for a conditional jump
so that the condition codes are set. straightforwardly. */
MODE is the mode of the inputs (in case they are const_int). static int
UNSIGNEDP nonzero says that X and Y are unsigned; cmp_available_p (mode, code, can_use_tst_p)
enum machine_mode mode;
enum rtx_code code;
int can_use_tst_p;
{
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))
return 1;
mode = GET_MODE_WIDER_MODE (mode);
} while (mode != VOIDmode);
return 0;
}
/* This function is called when we are going to emit a compare instruction that
compares the values found in *PX and *PY, using the rtl operator COMPARISON.
*PMODE is the mode of the inputs (in case they are const_int).
*PUNSIGNEDP nonzero says that the operands are unsigned;
this matters if they need to be widened. this matters if they need to be widened.
If they have mode BLKmode, then SIZE specifies the size of both X and Y, If they have mode BLKmode, then SIZE specifies the size of both operands,
and ALIGN specifies the known shared alignment of X and Y. and ALIGN specifies the known shared alignment of the operands.
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). This function performs all the setup necessary so that the caller only has
It is ignored for fixed-point and block comparisons; to emit a single comparison insn. This setup can involve doing a BLKmode
it is used only for floating-point comparisons. */ comparison or emitting a library call to perform the comparison if no insn
is available to handle it.
The values which are passed in through pointers can be modified; the caller
should perform the comparison on the modified values. */
void void
emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) prepare_cmp_insn (px, py, comparison, size, pmode, punsignedp, align)
rtx x, y; rtx *px, *py;
enum rtx_code comparison; enum rtx_code comparison;
rtx size; rtx size;
enum machine_mode mode; enum machine_mode *pmode;
int unsignedp; int *punsignedp;
int align; int align;
{ {
enum machine_mode mode = *pmode;
rtx x = *px, y = *py;
int unsignedp = *punsignedp;
enum mode_class class; enum mode_class class;
enum machine_mode wider_mode;
class = GET_MODE_CLASS (mode); class = GET_MODE_CLASS (mode);
...@@ -3046,6 +3070,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) ...@@ -3046,6 +3070,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
if (mode == BLKmode) if (mode == BLKmode)
{ {
rtx result;
enum machine_mode result_mode;
emit_queue (); emit_queue ();
x = protect_from_queue (x, 0); x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0); y = protect_from_queue (y, 0);
...@@ -3057,12 +3084,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) ...@@ -3057,12 +3084,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
&& GET_CODE (size) == CONST_INT && GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
{ {
enum machine_mode result_mode result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
= insn_operand_mode[(int) CODE_FOR_cmpstrqi][0]; result = gen_reg_rtx (result_mode);
rtx result = gen_reg_rtx (result_mode);
emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align))); emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align)));
emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
result_mode, 0, 0);
} }
else else
#endif #endif
...@@ -3071,33 +3095,25 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) ...@@ -3071,33 +3095,25 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
&& GET_CODE (size) == CONST_INT && GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
{ {
enum machine_mode result_mode result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
= insn_operand_mode[(int) CODE_FOR_cmpstrhi][0]; result = gen_reg_rtx (result_mode);
rtx result = gen_reg_rtx (result_mode);
emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align))); emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align)));
emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
result_mode, 0, 0);
} }
else else
#endif #endif
#ifdef HAVE_cmpstrsi #ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi) if (HAVE_cmpstrsi)
{ {
enum machine_mode result_mode result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
= insn_operand_mode[(int) CODE_FOR_cmpstrsi][0]; result = gen_reg_rtx (result_mode);
rtx result = gen_reg_rtx (result_mode);
size = protect_from_queue (size, 0); size = protect_from_queue (size, 0);
emit_insn (gen_cmpstrsi (result, x, y, emit_insn (gen_cmpstrsi (result, x, y,
convert_to_mode (SImode, size, 1), convert_to_mode (SImode, size, 1),
GEN_INT (align))); GEN_INT (align)));
emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
result_mode, 0, 0);
} }
else else
#endif #endif
{ {
rtx result;
#ifdef TARGET_MEM_FUNCTIONS #ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memcmp_libfunc, 0, emit_library_call (memcmp_libfunc, 0,
TYPE_MODE (integer_type_node), 3, TYPE_MODE (integer_type_node), 3,
...@@ -3119,83 +3135,24 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) ...@@ -3119,83 +3135,24 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
register so reload doesn't clobber the value if it needs register so reload doesn't clobber the value if it needs
the return register for a spill reg. */ the return register for a spill reg. */
result = gen_reg_rtx (TYPE_MODE (integer_type_node)); result = gen_reg_rtx (TYPE_MODE (integer_type_node));
result_mode = TYPE_MODE (integer_type_node);
emit_move_insn (result, emit_move_insn (result,
hard_libcall_value (TYPE_MODE (integer_type_node))); hard_libcall_value (result_mode));
emit_cmp_insn (result,
const0_rtx, comparison, NULL_RTX,
TYPE_MODE (integer_type_node), 0, 0);
} }
*px = result;
*py = const0_rtx;
*pmode = result_mode;
return; return;
} }
/* Handle some compares against zero. */ *px = x;
*py = y;
if (y == CONST0_RTX (mode) if (cmp_available_p (mode, comparison, y == CONST0_RTX (mode)))
&& tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) tst_optab->handlers[(int) mode].insn_code;
emit_queue ();
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
/* Now, if insn does accept these operands, put them into pseudos. */
if (! (*insn_operand_predicate[icode][0])
(x, insn_operand_mode[icode][0]))
x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
emit_insn (GEN_FCN (icode) (x));
return; return;
}
/* Handle compares for which there is a directly suitable insn. */
if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) cmp_optab->handlers[(int) mode].insn_code;
emit_queue ();
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
/* Now, if insn doesn't accept these operands, put them into pseudos. */
if (! (*insn_operand_predicate[icode][0])
(x, insn_operand_mode[icode][0]))
x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
if (! (*insn_operand_predicate[icode][1])
(y, insn_operand_mode[icode][1]))
y = copy_to_mode_reg (insn_operand_mode[icode][1], y);
emit_insn (GEN_FCN (icode) (x, y));
return;
}
/* Try widening if we can find a direct insn that way. */
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
{
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (cmp_optab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
{
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
x = convert_modes (wider_mode, mode, x, unsignedp);
y = convert_modes (wider_mode, mode, y, unsignedp);
emit_cmp_insn (x, y, comparison, NULL_RTX,
wider_mode, unsignedp, align);
return;
}
}
}
/* Handle a lib call just for the mode we are using. */ /* Handle a lib call just for the mode we are using. */
if (cmp_optab->handlers[(int) mode].libfunc if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
&& class != MODE_FLOAT)
{ {
rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
rtx result; rtx result;
...@@ -3217,18 +3174,99 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) ...@@ -3217,18 +3174,99 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
/* Integer comparison returns a result that must be compared against 1, /* Integer comparison returns a result that must be compared against 1,
so that even if we do an unsigned compare afterward, so that even if we do an unsigned compare afterward,
there is still a value that can represent the result "less than". */ there is still a value that can represent the result "less than". */
emit_cmp_insn (result, const1_rtx, *px = result;
comparison, NULL_RTX, word_mode, unsignedp, 0); *py = const1_rtx;
*pmode = word_mode;
return; return;
} }
if (class == MODE_FLOAT) if (class == MODE_FLOAT)
emit_float_lib_cmp (x, y, comparison); prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp);
else else
abort (); abort ();
} }
/* Before emitting an insn with code ICODE, make sure that X, which is going
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
prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
int icode;
rtx x;
int opnum;
enum machine_mode mode, wider_mode;
int unsignedp;
{
x = protect_from_queue (x, 0);
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);
return x;
}
/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
we can do the comparison.
The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
be NULL_RTX which indicates that only a comparison is to be generated. */
static void
emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
rtx x, y;
enum machine_mode mode;
enum rtx_code comparison;
int unsignedp;
rtx label;
{
rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode = mode;
/* Try combined insns first. */
do
{
enum insn_code icode;
PUT_MODE (test, wider_mode);
/* Handle some compares against zero. */
icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
{
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
emit_insn (GEN_FCN (icode) (x));
if (label)
emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
return;
}
/* Handle compares for which there is a directly suitable insn. */
icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
if (icode != CODE_FOR_nothing)
{
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
emit_insn (GEN_FCN (icode) (x, y));
if (label)
emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
return;
}
if (class != MODE_INT && class != MODE_FLOAT
&& class != MODE_COMPLEX_FLOAT)
break;
wider_mode = GET_MODE_WIDER_MODE (wider_mode);
} while (wider_mode != VOIDmode);
abort ();
}
/* Generate code to compare X with Y so that the condition codes are /* Generate code to compare X with Y so that the condition codes are
set and to jump to LABEL if the condition is true. If X is a set and to jump to LABEL if the condition is true. If X is a
constant and Y is not a constant, then the comparison is swapped to constant and Y is not a constant, then the comparison is swapped to
...@@ -3281,11 +3319,24 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label) ...@@ -3281,11 +3319,24 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
op0 = force_reg (mode, op0); op0 = force_reg (mode, op0);
#endif #endif
emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align); emit_queue ();
if (unsignedp) if (unsignedp)
comparison = unsigned_condition (comparison); comparison = unsigned_condition (comparison);
emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label)); prepare_cmp_insn (&op0, &op1, comparison, size, &mode, &unsignedp, align);
emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
}
/* Like emit_cmp_and_jump_insns, but generate only the comparison. */
void
emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
rtx x, y;
enum rtx_code comparison;
rtx size;
enum machine_mode mode;
int unsignedp;
int align;
{
emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0);
} }
...@@ -3310,10 +3361,13 @@ can_compare_p (mode) ...@@ -3310,10 +3361,13 @@ can_compare_p (mode)
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */
void void
emit_float_lib_cmp (x, y, comparison) prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp)
rtx x, y; rtx *px, *py;
enum rtx_code comparison; enum rtx_code comparison;
enum machine_mode *pmode;
int *punsignedp;
{ {
rtx x = *px, y = *py;
enum machine_mode mode = GET_MODE (x); enum machine_mode mode = GET_MODE (x);
rtx libfunc = 0; rtx libfunc = 0;
rtx result; rtx result;
...@@ -3481,9 +3535,9 @@ emit_float_lib_cmp (x, y, comparison) ...@@ -3481,9 +3535,9 @@ emit_float_lib_cmp (x, y, comparison)
{ {
x = protect_from_queue (x, 0); x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0); y = protect_from_queue (y, 0);
x = convert_to_mode (wider_mode, x, 0); *px = convert_to_mode (wider_mode, x, 0);
y = convert_to_mode (wider_mode, y, 0); *py = convert_to_mode (wider_mode, y, 0);
emit_float_lib_cmp (x, y, comparison); prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp);
return; return;
} }
} }
...@@ -3501,9 +3555,10 @@ emit_float_lib_cmp (x, y, comparison) ...@@ -3501,9 +3555,10 @@ emit_float_lib_cmp (x, y, comparison)
the return register for a spill reg. */ the return register for a spill reg. */
result = gen_reg_rtx (word_mode); result = gen_reg_rtx (word_mode);
emit_move_insn (result, hard_libcall_value (word_mode)); emit_move_insn (result, hard_libcall_value (word_mode));
*px = result;
emit_cmp_insn (result, const0_rtx, comparison, *py = const0_rtx;
NULL_RTX, word_mode, 0, 0); *pmode = word_mode;
*punsignedp = 0;
} }
/* Generate code to indirectly jump to a location given in the rtx LOC. */ /* Generate code to indirectly jump to a location given in the rtx LOC. */
......
...@@ -339,15 +339,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before, ...@@ -339,15 +339,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
} }
else if (GET_CODE (last_loop_insn) == JUMP_INSN) else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{ {
rtx prev = PREV_INSN (last_loop_insn);
delete_insn (last_loop_insn);
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* The immediately preceding insn is a compare which must be /* The immediately preceding insn may be a compare which must be
deleted. */ deleted. */
delete_insn (last_loop_insn); if (sets_cc0_p (prev))
delete_insn (PREV_INSN (last_loop_insn)); delete_insn (prev);
#else
/* The immediately preceding insn may not be the compare, so don't
delete it. */
delete_insn (last_loop_insn);
#endif #endif
} }
return; return;
...@@ -479,14 +477,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before, ...@@ -479,14 +477,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end = PREV_INSN (PREV_INSN (last_loop_insn)); copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
else if (GET_CODE (last_loop_insn) == JUMP_INSN) else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{ {
copy_end = PREV_INSN (last_loop_insn);
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* The instruction immediately before the JUMP_INSN is a compare /* The instruction immediately before the JUMP_INSN may be a compare
instruction which we do not want to copy. */ instruction which we do not want to copy. */
copy_end = PREV_INSN (PREV_INSN (last_loop_insn)); if (sets_cc0_p (PREV_INSN (copy_end)))
#else copy_end = PREV_INSN (copy_end);
/* The instruction immediately before the JUMP_INSN may not be the
compare, so we must copy it. */
copy_end = PREV_INSN (last_loop_insn);
#endif #endif
} }
else else
...@@ -520,17 +516,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before, ...@@ -520,17 +516,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
} }
else if (GET_CODE (last_loop_insn) == JUMP_INSN) else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{ {
insert_before = last_loop_insn;
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* The instruction immediately before the JUMP_INSN is a compare /* The instruction immediately before the JUMP_INSN may be a compare
instruction which we do not want to copy or delete. */ instruction which we do not want to copy or delete. */
insert_before = PREV_INSN (last_loop_insn); if (sets_cc0_p (PREV_INSN (insert_before)))
copy_end = PREV_INSN (insert_before); insert_before = PREV_INSN (insert_before);
#else
/* The instruction immediately before the JUMP_INSN may not be the
compare, so we must copy it. */
insert_before = last_loop_insn;
copy_end = PREV_INSN (last_loop_insn);
#endif #endif
copy_end = PREV_INSN (insert_before);
} }
else else
{ {
...@@ -793,9 +786,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before, ...@@ -793,9 +786,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end_luid--; copy_end_luid--;
/* If we have a target that uses cc0, then we also must not duplicate /* If we have a target that uses cc0, then we also must not duplicate
the insn that sets cc0 before the jump insn. */ the insn that sets cc0 before the jump insn, if one is present. */
#ifdef HAVE_cc0 #ifdef HAVE_cc0
if (GET_CODE (copy_end) == JUMP_INSN) if (GET_CODE (copy_end) == JUMP_INSN && sets_cc0_p (PREV_INSN (copy_end)))
copy_end_luid--; copy_end_luid--;
#endif #endif
...@@ -1036,14 +1029,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before, ...@@ -1036,14 +1029,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end = PREV_INSN (PREV_INSN (last_loop_insn)); copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
else if (GET_CODE (last_loop_insn) == JUMP_INSN) else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{ {
copy_end = PREV_INSN (last_loop_insn);
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* The immediately preceding insn is a compare which we do not /* The immediately preceding insn may be a compare which we do not
want to copy. */ want to copy. */
copy_end = PREV_INSN (PREV_INSN (last_loop_insn)); if (sets_cc0_p (PREV_INSN (copy_end)))
#else copy_end = PREV_INSN (copy_end);
/* The immediately preceding insn may not be a compare, so we
must copy it. */
copy_end = PREV_INSN (last_loop_insn);
#endif #endif
} }
else else
...@@ -1098,17 +1089,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before, ...@@ -1098,17 +1089,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
} }
else else
{ {
#ifdef HAVE_cc0
/* The immediately preceding insn is a compare which we do not
want to copy. */
insert_before = PREV_INSN (last_loop_insn);
copy_end = PREV_INSN (insert_before);
#else
/* The immediately preceding insn may not be a compare, so we
must copy it. */
insert_before = last_loop_insn; insert_before = last_loop_insn;
copy_end = PREV_INSN (last_loop_insn); #ifdef HAVE_cc0
/* The instruction immediately before the JUMP_INSN may be a compare
instruction which we do not want to copy or delete. */
if (sets_cc0_p (PREV_INSN (insert_before)))
insert_before = PREV_INSN (insert_before);
#endif #endif
copy_end = PREV_INSN (insert_before);
} }
/* Set unroll type to MODULO now. */ /* Set unroll type to MODULO now. */
...@@ -2089,7 +2077,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration, ...@@ -2089,7 +2077,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
if (condjump_p (insn) && !simplejump_p (insn) && map->last_pc_value) if (condjump_p (insn) && !simplejump_p (insn) && map->last_pc_value)
{ {
#ifdef HAVE_cc0 #ifdef HAVE_cc0
/* The previous insn set cc0 for us. So delete it. */ /* If the previous insn set cc0 for us, delete it. */
if (sets_cc0_p (PREV_INSN (copy)))
delete_insn (PREV_INSN (copy)); delete_insn (PREV_INSN (copy));
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment