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>
* Makefile.in (insn-recog.o): Update dependencies.
......
......@@ -4093,6 +4093,9 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
rtx last = get_last_insn ();
rtx pattern, comparison;
if (unsignedp)
code = unsigned_condition (code);
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
......@@ -4492,15 +4495,10 @@ emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
target = gen_reg_rtx (GET_MODE (target));
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 ();
if (bcc_gen_fctn[(int) code] == 0)
abort ();
do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX, 0,
NULL_RTX, label);
emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
emit_move_insn (target, const0_rtx);
emit_label (label);
......@@ -4519,13 +4517,13 @@ emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
static void
do_cmp_and_jump (arg1, arg2, op, mode, label)
rtx arg1, arg2, label;
enum rtx_code op;
enum machine_mode mode;
enum rtx_code op;
enum machine_mode mode;
{
/* 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))
{
rtx label2 = gen_label_rtx ();
......
......@@ -152,8 +152,7 @@ static rtx expand_increment PROTO((tree, int, int));
static void preexpand_calls PROTO((tree));
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_for_compare PROTO((rtx, rtx, rtx));
static rtx compare PROTO((tree, enum rtx_code, enum rtx_code));
static void do_compare_and_jump PROTO((tree, enum rtx_code, enum rtx_code, rtx, rtx));
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
......@@ -7297,7 +7296,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))
{
if (code == MAX_EXPR)
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
......@@ -7305,29 +7304,15 @@ expand_expr (exp, target, tmode, modifier)
else
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
op1, target, NULL_RTX, op0);
emit_move_insn (target, op1);
}
else
{
if (code == MAX_EXPR)
temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
? compare_from_rtx (target, op1, GEU, 1, mode, NULL_RTX, 0)
: compare_from_rtx (target, op1, GE, 0, mode, NULL_RTX, 0));
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);
}
int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
unsignedp, mode, NULL_RTX, 0, NULL_RTX,
op0);
}
emit_move_insn (target, op1);
emit_label (op0);
return target;
......@@ -8626,7 +8611,6 @@ do_jump (exp, if_false_label, if_true_label)
These cases set DROP_THROUGH_LABEL nonzero. */
rtx drop_through_label = 0;
rtx temp;
rtx comparison = 0;
int i;
tree type;
enum machine_mode mode;
......@@ -8692,10 +8676,10 @@ do_jump (exp, if_false_label, if_true_label)
case MINUS_EXPR:
/* Non-zero iff operands of minus differ. */
comparison = compare (build (NE_EXPR, TREE_TYPE (exp),
TREE_OPERAND (exp, 0),
TREE_OPERAND (exp, 1)),
NE, NE);
do_compare_and_jump (build (NE_EXPR, TREE_TYPE (exp),
TREE_OPERAND (exp, 0),
TREE_OPERAND (exp, 1)),
NE, NE, if_false_label, if_true_label);
break;
case BIT_AND_EXPR:
......@@ -8854,7 +8838,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_false_label, if_true_label);
else
comparison = compare (exp, EQ, EQ);
do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
break;
}
......@@ -8894,7 +8878,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_true_label, if_false_label);
else
comparison = compare (exp, NE, NE);
do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
break;
}
......@@ -8904,7 +8888,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
else
comparison = compare (exp, LT, LTU);
do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
break;
case LE_EXPR:
......@@ -8913,7 +8897,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
else
comparison = compare (exp, LE, LEU);
do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
break;
case GT_EXPR:
......@@ -8922,7 +8906,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
else
comparison = compare (exp, GT, GTU);
do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
break;
case GE_EXPR:
......@@ -8931,7 +8915,7 @@ do_jump (exp, if_false_label, if_true_label)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
else
comparison = compare (exp, GE, GEU);
do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
break;
default:
......@@ -8947,42 +8931,28 @@ do_jump (exp, if_false_label, if_true_label)
temp = copy_to_reg (temp);
#endif
do_pending_stack_adjust ();
if (GET_CODE (temp) == CONST_INT)
comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx);
else if (GET_CODE (temp) == LABEL_REF)
comparison = const_true_rtx;
/* Do any postincrements in the expression that was tested. */
emit_queue ();
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
&& !can_compare_p (GET_MODE (temp)))
&& ! can_compare_p (GET_MODE (temp)))
/* 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)
comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)),
NE, TREE_UNSIGNED (TREE_TYPE (exp)),
GET_MODE (temp), NULL_RTX, 0);
do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
NE, TREE_UNSIGNED (TREE_TYPE (exp)),
GET_MODE (temp), NULL_RTX, 0,
if_false_label, if_true_label);
else
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 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)
rtx op0 = 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)));
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 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. */
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);
do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label);
}
/* 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
}
/* All but high-order word must be compared as unsigned. */
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);
do_compare_rtx_and_jump (op0_word, op1_word, GT,
(unsignedp || i > 0), word_mode, NULL_RTX, 0,
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);
do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, 0, NULL_RTX, if_false_label);
}
if (if_false_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 ();
for (i = 0; i < nwords; i++)
{
rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode),
operand_subword_force (op1, i, mode),
EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
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);
}
do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
operand_subword_force (op1, i, mode),
EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
word_mode, NULL_RTX, 0, if_false_label,
NULL_RTX);
if (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)
if (part != 0)
{
rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode,
NULL_RTX, 0);
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);
do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
NULL_RTX, 0, if_false_label, if_true_label);
return;
}
......@@ -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 ();
for (i = 0; i < nwords; i++)
{
rtx comp = compare_from_rtx (operand_subword_force (op0, i,
GET_MODE (op0)),
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);
}
do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
const0_rtx, EQ, 1, word_mode, NULL_RTX, 0,
if_false_label, NULL_RTX);
if (if_true_label)
emit_jump (if_true_label);
......@@ -9221,168 +9117,84 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
if (drop_through_label)
emit_label (drop_through_label);
}
/* Given a comparison expression in rtl form, output conditional branches to
IF_TRUE_LABEL, IF_FALSE_LABEL, or both. */
static void
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
case that, on some machines, emitting the branch would discard
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)
first = get_insns ();
else if (INSN_DELETED_P (first))
abort ();
else
first = NEXT_INSN (first);
/* Look for multiple branches in this sequence, as might be generated
for a multi-word integer comparison. */
br_count = 0;
branch = NULL_RTX;
for (insn = first; insn ; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{
branch = insn;
br_count += 1;
}
/* If we've got one branch at the end of the sequence,
we can try to reverse it. */
if (br_count == 1 && NEXT_INSN (branch) == NULL_RTX)
{
rtx insn_label;
insn_label = XEXP (condjump_label (branch), 0);
JUMP_LABEL (branch) = insn_label;
if (insn_label != if_false_label)
abort ();
if (invert_jump (branch, if_false_label))
return;
}
/* Multiple branches, or reversion failed. Convert to branches
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;
insn_label = XEXP (condjump_label (insn), 0);
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
/* Generate code for a comparison of OP0 and OP1 with rtx code CODE.
(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.
The decision as to signed or unsigned comparison must be made by the caller.
We force a stack adjustment unless there are currently
things pushed on the stack that aren't yet used. */
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;
If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
compared.
If ALIGN is non-zero, it is the alignment of this type; if zero, the
size of MODE should be used. */
rtx
compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
register rtx op0, op1;
enum rtx_code code;
int unsignedp;
enum machine_mode mode;
rtx size;
int align;
{
register rtx op0, op1;
register tree type;
register enum machine_mode mode;
int unsignedp;
enum rtx_code code;
rtx tem;
/* 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);
type = TREE_TYPE (TREE_OPERAND (exp, 0));
mode = TYPE_MODE (type);
unsignedp = TREE_UNSIGNED (type);
code = unsignedp ? unsigned_code : signed_code;
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
#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))
if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
|| (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
{
rtx new_op0 = gen_reg_rtx (mode);
emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
op0 = new_op0;
tem = op0;
op0 = op1;
op1 = tem;
code = swap_condition (code);
}
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))
if (flag_force_mem)
{
rtx new_op1 = gen_reg_rtx (mode);
op0 = force_not_mem (op0);
op1 = force_not_mem (op1);
}
emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
op1 = new_op1;
do_pending_stack_adjust ();
if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
&& (tem = simplify_relational_operation (code, mode, op0, op1)) != 0)
return tem;
#if 0
/* 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 this is a signed equality comparison, we can do it as an
unsigned comparison since zero-extension is cheaper than sign
extension and comparisons with zero are done as unsigned. This is
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)
{
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
unsignedp = 1;
}
#endif
emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
return compare_from_rtx (op0, op1, code, unsignedp, mode,
((mode == BLKmode)
? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
}
/* 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.
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)
If ALIGN is non-zero, it is the alignment of this type; if zero, the
size of MODE should be used. */
rtx
compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
void
do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
if_false_label, if_true_label)
register rtx op0, op1;
enum rtx_code code;
int unsignedp;
enum machine_mode mode;
rtx size;
int align;
rtx if_false_label, if_true_label;
{
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 the other operand is not constant as well. */
......@@ -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
&& (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
/* There's no need to do this now that combine.c can eliminate lots of
......@@ -9447,10 +9283,90 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
unsignedp = 1;
}
#endif
emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
if (! if_true_label)
{
dummy_true_label = 1;
if_true_label = gen_label_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
......
......@@ -801,6 +801,9 @@ extern void do_jump PROTO((tree, rtx, rtx));
/* Generate rtl to compare two rtx's, will call emit_cmp_insn. */
extern rtx compare_from_rtx PROTO((rtx, rtx, enum rtx_code, 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). */
extern void do_tablejump PROTO((rtx, enum machine_mode, rtx, rtx, rtx));
......
......@@ -1998,7 +1998,7 @@ tidy_fallthru_edge (e, b, c)
#ifdef HAVE_cc0
/* If this was a conditional jump, we need to also delete
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);
#endif
......
......@@ -1958,8 +1958,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value)
{
#ifdef HAVE_cc0
/* The previous insn set cc0 for us. So delete it. */
delete_insn (PREV_INSN (copy));
/* If the previous insn set cc0 for us, delete it. */
if (sets_cc0_p (PREV_INSN (copy)))
delete_insn (PREV_INSN (copy));
#endif
/* If this is now a no-op, delete it. */
......
......@@ -267,6 +267,15 @@ 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, 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
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)
carry_out = gen_reg_rtx (word_mode);
carry_out = emit_store_flag_force (carry_out,
(binoptab == add_optab
? LTU : GTU),
? LT : GT),
x, op0_piece,
word_mode, 1, normalizep);
}
......@@ -1349,7 +1358,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* Get out carry from adding/subtracting carry in. */
carry_tmp = emit_store_flag_force (carry_tmp,
binoptab == add_optab
? LTU : GTU,
? LT : GT,
x, carry_in,
word_mode, 1, normalizep);
......@@ -2463,19 +2472,8 @@ expand_abs (mode, op0, target, safe)
do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
NULL_RTX, op1);
else
{
temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
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 ();
}
}
do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
NULL_RTX, 0, NULL_RTX, op1);
op0 = expand_unop (mode, neg_optab, target, target, 0);
if (op0 != target)
......@@ -2983,31 +2981,57 @@ emit_0_to_1_insn (x)
emit_move_insn (x, const1_rtx);
}
/* Generate code to compare X with Y
so that the condition codes are set.
/* Nonzero if we can perform a comparison of mode MODE for a conditional jump
straightforwardly. */
MODE is the mode of the inputs (in case they are const_int).
UNSIGNEDP nonzero says that X and Y are unsigned;
static int
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.
If they have mode BLKmode, then SIZE specifies the size of both X and Y,
and ALIGN specifies the known shared alignment of X and Y.
If they have mode BLKmode, then SIZE specifies the size of both operands,
and ALIGN specifies the known shared alignment of the operands.
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
It is ignored for fixed-point and block comparisons;
it is used only for floating-point comparisons. */
This function performs all the setup necessary so that the caller only has
to emit a single comparison insn. This setup can involve doing a BLKmode
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
emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
rtx x, y;
prepare_cmp_insn (px, py, comparison, size, pmode, punsignedp, align)
rtx *px, *py;
enum rtx_code comparison;
rtx size;
enum machine_mode mode;
int unsignedp;
enum machine_mode *pmode;
int *punsignedp;
int align;
{
enum machine_mode mode = *pmode;
rtx x = *px, y = *py;
int unsignedp = *punsignedp;
enum mode_class class;
enum machine_mode wider_mode;
class = GET_MODE_CLASS (mode);
......@@ -3046,6 +3070,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
if (mode == BLKmode)
{
rtx result;
enum machine_mode result_mode;
emit_queue ();
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
......@@ -3057,12 +3084,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
{
enum machine_mode result_mode
= insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
rtx result = gen_reg_rtx (result_mode);
result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
result = gen_reg_rtx (result_mode);
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
#endif
......@@ -3071,33 +3095,25 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
{
enum machine_mode result_mode
= insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
rtx result = gen_reg_rtx (result_mode);
result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
result = gen_reg_rtx (result_mode);
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
#endif
#ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi)
{
enum machine_mode result_mode
= insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
rtx result = gen_reg_rtx (result_mode);
result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
result = gen_reg_rtx (result_mode);
size = protect_from_queue (size, 0);
emit_insn (gen_cmpstrsi (result, x, y,
convert_to_mode (SImode, size, 1),
GEN_INT (align)));
emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
result_mode, 0, 0);
}
else
#endif
{
rtx result;
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memcmp_libfunc, 0,
TYPE_MODE (integer_type_node), 3,
......@@ -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
the return register for a spill reg. */
result = gen_reg_rtx (TYPE_MODE (integer_type_node));
result_mode = TYPE_MODE (integer_type_node);
emit_move_insn (result,
hard_libcall_value (TYPE_MODE (integer_type_node)));
emit_cmp_insn (result,
const0_rtx, comparison, NULL_RTX,
TYPE_MODE (integer_type_node), 0, 0);
hard_libcall_value (result_mode));
}
*px = result;
*py = const0_rtx;
*pmode = result_mode;
return;
}
/* Handle some compares against zero. */
if (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;
}
/* 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;
}
}
}
*px = x;
*py = y;
if (cmp_available_p (mode, comparison, y == CONST0_RTX (mode)))
return;
/* Handle a lib call just for the mode we are using. */
if (cmp_optab->handlers[(int) mode].libfunc
&& class != MODE_FLOAT)
if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
{
rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
rtx result;
......@@ -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,
so that even if we do an unsigned compare afterward,
there is still a value that can represent the result "less than". */
emit_cmp_insn (result, const1_rtx,
comparison, NULL_RTX, word_mode, unsignedp, 0);
*px = result;
*py = const1_rtx;
*pmode = word_mode;
return;
}
if (class == MODE_FLOAT)
emit_float_lib_cmp (x, y, comparison);
prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp);
else
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
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
......@@ -3281,11 +3319,24 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
op0 = force_reg (mode, op0);
#endif
emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align);
emit_queue ();
if (unsignedp)
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)
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */
void
emit_float_lib_cmp (x, y, comparison)
rtx x, y;
prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp)
rtx *px, *py;
enum rtx_code comparison;
enum machine_mode *pmode;
int *punsignedp;
{
rtx x = *px, y = *py;
enum machine_mode mode = GET_MODE (x);
rtx libfunc = 0;
rtx result;
......@@ -3481,9 +3535,9 @@ emit_float_lib_cmp (x, y, comparison)
{
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
x = convert_to_mode (wider_mode, x, 0);
y = convert_to_mode (wider_mode, y, 0);
emit_float_lib_cmp (x, y, comparison);
*px = convert_to_mode (wider_mode, x, 0);
*py = convert_to_mode (wider_mode, y, 0);
prepare_float_lib_cmp (px, py, comparison, pmode, punsignedp);
return;
}
}
......@@ -3501,9 +3555,10 @@ emit_float_lib_cmp (x, y, comparison)
the return register for a spill reg. */
result = gen_reg_rtx (word_mode);
emit_move_insn (result, hard_libcall_value (word_mode));
emit_cmp_insn (result, const0_rtx, comparison,
NULL_RTX, word_mode, 0, 0);
*px = result;
*py = const0_rtx;
*pmode = word_mode;
*punsignedp = 0;
}
/* 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,
}
else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{
rtx prev = PREV_INSN (last_loop_insn);
delete_insn (last_loop_insn);
#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. */
delete_insn (last_loop_insn);
delete_insn (PREV_INSN (last_loop_insn));
#else
/* The immediately preceding insn may not be the compare, so don't
delete it. */
delete_insn (last_loop_insn);
if (sets_cc0_p (prev))
delete_insn (prev);
#endif
}
return;
......@@ -479,14 +477,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{
copy_end = PREV_INSN (last_loop_insn);
#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. */
copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
#else
/* The instruction immediately before the JUMP_INSN may not be the
compare, so we must copy it. */
copy_end = PREV_INSN (last_loop_insn);
if (sets_cc0_p (PREV_INSN (copy_end)))
copy_end = PREV_INSN (copy_end);
#endif
}
else
......@@ -520,17 +516,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
}
else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{
insert_before = last_loop_insn;
#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. */
insert_before = PREV_INSN (last_loop_insn);
copy_end = 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);
if (sets_cc0_p (PREV_INSN (insert_before)))
insert_before = PREV_INSN (insert_before);
#endif
copy_end = PREV_INSN (insert_before);
}
else
{
......@@ -793,9 +786,9 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end_luid--;
/* 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
if (GET_CODE (copy_end) == JUMP_INSN)
if (GET_CODE (copy_end) == JUMP_INSN && sets_cc0_p (PREV_INSN (copy_end)))
copy_end_luid--;
#endif
......@@ -1036,14 +1029,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
else if (GET_CODE (last_loop_insn) == JUMP_INSN)
{
copy_end = PREV_INSN (last_loop_insn);
#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. */
copy_end = PREV_INSN (PREV_INSN (last_loop_insn));
#else
/* The immediately preceding insn may not be a compare, so we
must copy it. */
copy_end = PREV_INSN (last_loop_insn);
if (sets_cc0_p (PREV_INSN (copy_end)))
copy_end = PREV_INSN (copy_end);
#endif
}
else
......@@ -1098,17 +1089,14 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
}
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;
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
copy_end = PREV_INSN (insert_before);
}
/* Set unroll type to MODULO now. */
......@@ -2089,8 +2077,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
if (condjump_p (insn) && !simplejump_p (insn) && map->last_pc_value)
{
#ifdef HAVE_cc0
/* The previous insn set cc0 for us. So delete it. */
delete_insn (PREV_INSN (copy));
/* If the previous insn set cc0 for us, delete it. */
if (sets_cc0_p (PREV_INSN (copy)))
delete_insn (PREV_INSN (copy));
#endif
/* If this is now a no-op, delete it. */
......
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