mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-02 08:13:58 +08:00
re PR middle-end/25724 (Emits call to __cmpdi2 for long long comparison in switches)
PR middle-end/25724 * dojump.c (do_jump): Call do_compare_rtx_and_jump. (do_jump_parts_zero_rtx): New function renamed from do_jump_parts_equality_rtx. Made static. Add a mode argument. (do_jump_parts_equality_rtx): New function split out from do_jump_parts_equality. Old implementation renamed as above. Call do_jump_parts_zero_rtx if either operand is zero. (do_jump_parts_equality): Call do_jump_parts_equality_rtx to do all of the heavy lifting. (do_compare_rtx_and_jump): Handle multi-word comparisons by calling either do_jump_by_parts_greater_rtx or do_jump_by_parts_equality_rtx. * expr.h (do_jump_by_parts_equality_rtx): Remove prototype. * expmed.c (do_cmp_and_jump): Now multi-word optimization has moved to do_compare_rtx_and_jump, call it directly. * stmt.c (do_jump_if_equal): Remove static prototype. Add a mode argument. Call do_compare_rtx_and_jump. (emit_case_nodes): Update calls to do_jump_if_equal. From-SVN: r110906
This commit is contained in:
parent
c0c84a897e
commit
feb0478035
@ -1,3 +1,24 @@
|
||||
2006-02-12 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
PR middle-end/25724
|
||||
* dojump.c (do_jump): Call do_compare_rtx_and_jump.
|
||||
(do_jump_parts_zero_rtx): New function renamed from
|
||||
do_jump_parts_equality_rtx. Made static. Add a mode argument.
|
||||
(do_jump_parts_equality_rtx): New function split out from
|
||||
do_jump_parts_equality. Old implementation renamed as above.
|
||||
Call do_jump_parts_zero_rtx if either operand is zero.
|
||||
(do_jump_parts_equality): Call do_jump_parts_equality_rtx to
|
||||
do all of the heavy lifting.
|
||||
(do_compare_rtx_and_jump): Handle multi-word comparisons by
|
||||
calling either do_jump_by_parts_greater_rtx or
|
||||
do_jump_by_parts_equality_rtx.
|
||||
* expr.h (do_jump_by_parts_equality_rtx): Remove prototype.
|
||||
* expmed.c (do_cmp_and_jump): Now multi-word optimization has
|
||||
moved to do_compare_rtx_and_jump, call it directly.
|
||||
* stmt.c (do_jump_if_equal): Remove static prototype. Add a
|
||||
mode argument. Call do_compare_rtx_and_jump.
|
||||
(emit_case_nodes): Update calls to do_jump_if_equal.
|
||||
|
||||
2006-02-12 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
PR rtl-optimization/26225
|
||||
|
188
gcc/dojump.c
188
gcc/dojump.c
@ -1,6 +1,6 @@
|
||||
/* Convert tree expression to rtl instructions, for GNU compiler.
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
@ -586,38 +586,20 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
normal:
|
||||
temp = expand_normal (exp);
|
||||
do_pending_stack_adjust ();
|
||||
|
||||
if (GET_CODE (temp) == CONST_INT
|
||||
|| (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
|
||||
|| 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 (NE, GET_MODE (temp), ccp_jump))
|
||||
/* Note swapping the labels gives us not-equal. */
|
||||
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
|
||||
else
|
||||
/* The RTL optimizers prefer comparisons against pseudos. */
|
||||
if (GET_CODE (temp) == SUBREG)
|
||||
{
|
||||
gcc_assert (GET_MODE (temp) != VOIDmode);
|
||||
|
||||
/* The RTL optimizers prefer comparisons against pseudos. */
|
||||
if (GET_CODE (temp) == SUBREG)
|
||||
{
|
||||
/* Compare promoted variables in their promoted mode. */
|
||||
if (SUBREG_PROMOTED_VAR_P (temp)
|
||||
&& REG_P (XEXP (temp, 0)))
|
||||
temp = XEXP (temp, 0);
|
||||
else
|
||||
temp = copy_to_reg (temp);
|
||||
}
|
||||
do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
|
||||
NE, TYPE_UNSIGNED (TREE_TYPE (exp)),
|
||||
GET_MODE (temp), NULL_RTX,
|
||||
if_false_label, if_true_label);
|
||||
/* Compare promoted variables in their promoted mode. */
|
||||
if (SUBREG_PROMOTED_VAR_P (temp)
|
||||
&& REG_P (XEXP (temp, 0)))
|
||||
temp = XEXP (temp, 0);
|
||||
else
|
||||
temp = copy_to_reg (temp);
|
||||
}
|
||||
do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
|
||||
NE, TYPE_UNSIGNED (TREE_TYPE (exp)),
|
||||
GET_MODE (temp), NULL_RTX,
|
||||
if_false_label, if_true_label);
|
||||
}
|
||||
|
||||
if (drop_through_label)
|
||||
@ -695,43 +677,17 @@ do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
|
||||
if (drop_through_label)
|
||||
emit_label (drop_through_label);
|
||||
}
|
||||
|
||||
/* Given an EQ_EXPR expression EXP for values too wide to be compared
|
||||
with one insn, test the comparison and jump to the appropriate label. */
|
||||
|
||||
/* Jump according to whether OP0 is 0. We assume that OP0 has an integer
|
||||
mode, MODE, that is too wide for the available compare insns. Either
|
||||
Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
|
||||
to indicate drop through. */
|
||||
|
||||
static void
|
||||
do_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
|
||||
rtx if_false_label, rtx if_true_label)
|
||||
{
|
||||
rtx op0 = expand_normal (TREE_OPERAND (exp, 0));
|
||||
rtx op1 = expand_normal (TREE_OPERAND (exp, 1));
|
||||
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
|
||||
int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
|
||||
int i;
|
||||
rtx drop_through_label = 0;
|
||||
|
||||
if (! if_false_label)
|
||||
drop_through_label = if_false_label = gen_label_rtx ();
|
||||
|
||||
for (i = 0; i < nwords; i++)
|
||||
do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
|
||||
operand_subword_force (op1, i, mode),
|
||||
EQ, TYPE_UNSIGNED (TREE_TYPE (exp)),
|
||||
word_mode, NULL_RTX, if_false_label, NULL_RTX);
|
||||
|
||||
if (if_true_label)
|
||||
emit_jump (if_true_label);
|
||||
if (drop_through_label)
|
||||
emit_label (drop_through_label);
|
||||
}
|
||||
|
||||
/* Jump according to whether OP0 is 0.
|
||||
We assume that OP0 has an integer mode that is too wide
|
||||
for the available compare insns. */
|
||||
|
||||
void
|
||||
do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
|
||||
{
|
||||
int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
|
||||
int nwords = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
|
||||
rtx part;
|
||||
int i;
|
||||
rtx drop_through_label = 0;
|
||||
@ -771,6 +727,58 @@ do_jump_by_parts_equality_rtx (rtx op0, rtx if_false_label, rtx if_true_label)
|
||||
if (drop_through_label)
|
||||
emit_label (drop_through_label);
|
||||
}
|
||||
|
||||
/* Test for the equality of two RTX expressions OP0 and OP1 in mode MODE,
|
||||
where MODE is an integer mode too wide to be compared with one insn.
|
||||
Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
|
||||
to indicate drop through. */
|
||||
|
||||
static void
|
||||
do_jump_by_parts_equality_rtx (enum machine_mode mode, rtx op0, rtx op1,
|
||||
rtx if_false_label, rtx if_true_label)
|
||||
{
|
||||
int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
|
||||
rtx drop_through_label = 0;
|
||||
int i;
|
||||
|
||||
if (op1 == const0_rtx)
|
||||
{
|
||||
do_jump_by_parts_zero_rtx (mode, op0, if_false_label, if_true_label);
|
||||
return;
|
||||
}
|
||||
else if (op0 == const0_rtx)
|
||||
{
|
||||
do_jump_by_parts_zero_rtx (mode, op1, if_false_label, if_true_label);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! if_false_label)
|
||||
drop_through_label = if_false_label = gen_label_rtx ();
|
||||
|
||||
for (i = 0; i < nwords; i++)
|
||||
do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
|
||||
operand_subword_force (op1, i, mode),
|
||||
EQ, 0, word_mode, NULL_RTX,
|
||||
if_false_label, NULL_RTX);
|
||||
|
||||
if (if_true_label)
|
||||
emit_jump (if_true_label);
|
||||
if (drop_through_label)
|
||||
emit_label (drop_through_label);
|
||||
}
|
||||
|
||||
/* Given an EQ_EXPR expression EXP for values too wide to be compared
|
||||
with one insn, test the comparison and jump to the appropriate label. */
|
||||
|
||||
static void
|
||||
do_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
|
||||
{
|
||||
rtx op0 = expand_normal (TREE_OPERAND (exp, 0));
|
||||
rtx op1 = expand_normal (TREE_OPERAND (exp, 1));
|
||||
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
|
||||
do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label,
|
||||
if_true_label);
|
||||
}
|
||||
|
||||
/* Generate code for a comparison of OP0 and OP1 with rtx code CODE.
|
||||
MODE is the machine mode of the comparison, not of the result.
|
||||
@ -886,14 +894,60 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
|
||||
unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
if_true_label);
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& ! can_compare_p (code, mode, ccp_jump))
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case LTU:
|
||||
do_jump_by_parts_greater_rtx (mode, 1, op1, op0,
|
||||
if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case LEU:
|
||||
do_jump_by_parts_greater_rtx (mode, 1, op0, op1,
|
||||
if_true_label, if_false_label);
|
||||
break;
|
||||
|
||||
case LT:
|
||||
do_jump_by_parts_greater_rtx (mode, 0, op1, op0,
|
||||
if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case GT:
|
||||
do_jump_by_parts_greater_rtx (mode, 0, op0, op1,
|
||||
if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case GE:
|
||||
do_jump_by_parts_greater_rtx (mode, 0, op1, op0,
|
||||
if_true_label, if_false_label);
|
||||
break;
|
||||
|
||||
case EQ:
|
||||
do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label,
|
||||
if_true_label);
|
||||
break;
|
||||
|
||||
case NE:
|
||||
do_jump_by_parts_equality_rtx (mode, op0, op1, if_true_label,
|
||||
if_false_label);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
else
|
||||
emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
|
||||
if_true_label);
|
||||
|
||||
if (if_false_label)
|
||||
emit_jump (if_false_label);
|
||||
|
65
gcc/expmed.c
65
gcc/expmed.c
@ -1,7 +1,8 @@
|
||||
/* Medium-level subroutines: convert bit-field store and extract
|
||||
and shifts, multiplies and divides to rtl instructions.
|
||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
@ -5564,66 +5565,14 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
|
||||
}
|
||||
|
||||
/* Perform possibly multi-word comparison and conditional jump to LABEL
|
||||
if ARG1 OP ARG2 true where ARG1 and ARG2 are of mode MODE
|
||||
|
||||
The algorithm is based on the code in expr.c:do_jump.
|
||||
|
||||
Note that this does not perform a general comparison. Only
|
||||
variants generated within expmed.c are correctly handled, others
|
||||
could be handled if needed. */
|
||||
if ARG1 OP ARG2 true where ARG1 and ARG2 are of mode MODE. This is
|
||||
now a thin wrapper around do_compare_rtx_and_jump. */
|
||||
|
||||
static void
|
||||
do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
|
||||
rtx label)
|
||||
{
|
||||
/* If this mode is an integer too wide to compare properly,
|
||||
compare word by word. Rely on cse to optimize constant cases. */
|
||||
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& ! can_compare_p (op, mode, ccp_jump))
|
||||
{
|
||||
rtx label2 = gen_label_rtx ();
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case LTU:
|
||||
do_jump_by_parts_greater_rtx (mode, 1, arg2, arg1, label2, label);
|
||||
break;
|
||||
|
||||
case LEU:
|
||||
do_jump_by_parts_greater_rtx (mode, 1, arg1, arg2, label, label2);
|
||||
break;
|
||||
|
||||
case LT:
|
||||
do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label2, label);
|
||||
break;
|
||||
|
||||
case GT:
|
||||
do_jump_by_parts_greater_rtx (mode, 0, arg1, arg2, label2, label);
|
||||
break;
|
||||
|
||||
case GE:
|
||||
do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label, label2);
|
||||
break;
|
||||
|
||||
/* do_jump_by_parts_equality_rtx compares with zero. Luckily
|
||||
that's the only equality operations we do */
|
||||
case EQ:
|
||||
gcc_assert (arg2 == const0_rtx && mode == GET_MODE(arg1));
|
||||
do_jump_by_parts_equality_rtx (arg1, label2, label);
|
||||
break;
|
||||
|
||||
case NE:
|
||||
gcc_assert (arg2 == const0_rtx && mode == GET_MODE(arg1));
|
||||
do_jump_by_parts_equality_rtx (arg1, label, label2);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
emit_label (label2);
|
||||
}
|
||||
else
|
||||
emit_cmp_and_jump_insns (arg1, arg2, op, NULL_RTX, mode, 0, label);
|
||||
int unsignedp = (op == LTU || op == LEU || op == GTU || op == GEU);
|
||||
do_compare_rtx_and_jump (arg1, arg2, op, unsignedp, mode,
|
||||
NULL_RTX, NULL_RTX, label);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Definitions for code generation pass of GNU compiler.
|
||||
Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -743,7 +743,6 @@ extern void init_all_optabs (void);
|
||||
/* Call this to initialize an optab function entry. */
|
||||
extern rtx init_one_libfunc (const char *);
|
||||
|
||||
extern void do_jump_by_parts_equality_rtx (rtx, rtx, rtx);
|
||||
extern void do_jump_by_parts_greater_rtx (enum machine_mode, int, rtx, rtx,
|
||||
rtx, rtx);
|
||||
|
||||
|
30
gcc/stmt.c
30
gcc/stmt.c
@ -1,6 +1,6 @@
|
||||
/* Expands front end tree to back end RTL for GCC
|
||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
|
||||
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -112,7 +112,6 @@ static bool check_unique_operand_names (tree, tree);
|
||||
static char *resolve_operand_name_1 (char *, tree, tree);
|
||||
static void expand_null_return_1 (void);
|
||||
static void expand_value_return (rtx);
|
||||
static void do_jump_if_equal (rtx, rtx, rtx, int);
|
||||
static int estimate_case_costs (case_node_ptr);
|
||||
static bool lshift_cheap_p (void);
|
||||
static int case_bit_test_cmp (const void *, const void *);
|
||||
@ -2588,21 +2587,14 @@ expand_case (tree exp)
|
||||
free_temp_slots ();
|
||||
}
|
||||
|
||||
/* Generate code to jump to LABEL if OP1 and OP2 are equal. */
|
||||
/* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. */
|
||||
|
||||
static void
|
||||
do_jump_if_equal (rtx op1, rtx op2, rtx label, int unsignedp)
|
||||
do_jump_if_equal (enum machine_mode mode, rtx op0, rtx op1, rtx label,
|
||||
int unsignedp)
|
||||
{
|
||||
if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
|
||||
{
|
||||
if (op1 == op2)
|
||||
emit_jump (label);
|
||||
}
|
||||
else
|
||||
emit_cmp_and_jump_insns (op1, op2, EQ, NULL_RTX,
|
||||
(GET_MODE (op1) == VOIDmode
|
||||
? GET_MODE (op2) : GET_MODE (op1)),
|
||||
unsignedp, label);
|
||||
do_compare_rtx_and_jump (op0, op1, EQ, unsignedp, mode,
|
||||
NULL_RTX, NULL_RTX, label);
|
||||
}
|
||||
|
||||
/* Not all case values are encountered equally. This function
|
||||
@ -2954,7 +2946,7 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
|
||||
/* Node is single valued. First see if the index expression matches
|
||||
this node and then check our children, if any. */
|
||||
|
||||
do_jump_if_equal (index,
|
||||
do_jump_if_equal (mode, index,
|
||||
convert_modes (mode, imode,
|
||||
expand_normal (node->low),
|
||||
unsignedp),
|
||||
@ -3007,7 +2999,7 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
|
||||
|
||||
/* See if the value matches what the right hand side
|
||||
wants. */
|
||||
do_jump_if_equal (index,
|
||||
do_jump_if_equal (mode, index,
|
||||
convert_modes (mode, imode,
|
||||
expand_normal (node->right->low),
|
||||
unsignedp),
|
||||
@ -3016,7 +3008,7 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
|
||||
|
||||
/* See if the value matches what the left hand side
|
||||
wants. */
|
||||
do_jump_if_equal (index,
|
||||
do_jump_if_equal (mode, index,
|
||||
convert_modes (mode, imode,
|
||||
expand_normal (node->left->low),
|
||||
unsignedp),
|
||||
@ -3082,7 +3074,7 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
|
||||
/* We cannot process node->right normally
|
||||
since we haven't ruled out the numbers less than
|
||||
this node's value. So handle node->right explicitly. */
|
||||
do_jump_if_equal (index,
|
||||
do_jump_if_equal (mode, index,
|
||||
convert_modes
|
||||
(mode, imode,
|
||||
expand_normal (node->right->low),
|
||||
@ -3113,7 +3105,7 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
|
||||
/* We cannot process node->left normally
|
||||
since we haven't ruled out the numbers less than
|
||||
this node's value. So handle node->left explicitly. */
|
||||
do_jump_if_equal (index,
|
||||
do_jump_if_equal (mode, index,
|
||||
convert_modes
|
||||
(mode, imode,
|
||||
expand_normal (node->left->low),
|
||||
|
Loading…
Reference in New Issue
Block a user