Commit 04a40cb9 by Steven Bosscher

expr.c (try_casesi): Remove bogus ATTRIBUTE_UNUSED markers.

gcc/
	* expr.c (try_casesi): Remove bogus ATTRIBUTE_UNUSED markers.
	* stmt.c (dump_case_nodes): New.
	(expand_case): Split out code generation parts into new functions.
	(expand_switch_as_decision_tree_p): Split out from expand_case.
	(emit_case_decision_tree): Likewise.
	(emit_case_dispatch_table): Likewise.

testsuite/
	* gcc.c-torture/compile/20000326-1.c: Fix to not optimize to empty.

From-SVN: r189285
parent 12c0399e
2012-07-05 Steven Bosscher <steven@gcc.gnu.org>
* expr.c (try_casesi): Remove bogus ATTRIBUTE_UNUSED markers.
* stmt.c (dump_case_nodes): New.
(expand_case): Split out code generation parts into new functions.
(expand_switch_as_decision_tree_p): Split out from expand_case.
(emit_case_decision_tree): Likewise.
(emit_case_dispatch_table): Likewise.
2012-07-05 Matthew Gretton-Dann <matthew.gretton-dann@arm.com> 2012-07-05 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* config/arm/iterators.md (SDF): New mode iterator. * config/arm/iterators.md (SDF): New mode iterator.
......
...@@ -10850,8 +10850,7 @@ do_store_flag (sepops ops, rtx target, enum machine_mode mode) ...@@ -10850,8 +10850,7 @@ do_store_flag (sepops ops, rtx target, enum machine_mode mode)
0 otherwise (i.e. if there is no casesi instruction). */ 0 otherwise (i.e. if there is no casesi instruction). */
int int
try_casesi (tree index_type, tree index_expr, tree minval, tree range, try_casesi (tree index_type, tree index_expr, tree minval, tree range,
rtx table_label ATTRIBUTE_UNUSED, rtx default_label, rtx table_label, rtx default_label, rtx fallback_label)
rtx fallback_label ATTRIBUTE_UNUSED)
{ {
struct expand_operand ops[5]; struct expand_operand ops[5];
enum machine_mode index_mode = SImode; enum machine_mode index_mode = SImode;
......
...@@ -1716,6 +1716,35 @@ add_case_node (struct case_node *head, tree type, tree low, tree high, ...@@ -1716,6 +1716,35 @@ add_case_node (struct case_node *head, tree type, tree low, tree high,
return r; return r;
} }
/* Dump ROOT, a list or tree of case nodes, to file. */
static void
dump_case_nodes (FILE *f, struct case_node *root,
int indent_step, int indent_level)
{
HOST_WIDE_INT low, high;
if (root == 0)
return;
indent_level++;
dump_case_nodes (f, root->left, indent_step, indent_level);
low = tree_low_cst (root->low, 0);
high = tree_low_cst (root->high, 0);
fputs (";; ", f);
if (high == low)
fprintf(f, "%*s" HOST_WIDE_INT_PRINT_DEC,
indent_step * indent_level, "", low);
else
fprintf(f, "%*s" HOST_WIDE_INT_PRINT_DEC " ... " HOST_WIDE_INT_PRINT_DEC,
indent_step * indent_level, "", low, high);
fputs ("\n", f);
dump_case_nodes (f, root->right, indent_step, indent_level);
}
#ifndef HAVE_casesi #ifndef HAVE_casesi
#define HAVE_casesi 0 #define HAVE_casesi 0
#endif #endif
...@@ -1738,161 +1767,85 @@ case_values_threshold (void) ...@@ -1738,161 +1767,85 @@ case_values_threshold (void)
return threshold; return threshold;
} }
/* Terminate a case (Pascal/Ada) or switch (C) statement /* Return true if a switch should be expanded as a decision tree.
in which ORIG_INDEX is the expression to be tested. RANGE is the difference between highest and lowest case.
If ORIG_TYPE is not NULL, it is the original ORIG_INDEX UNIQ is number of unique case node targets, not counting the default case.
type as given in the source before any compiler conversions. COUNT is the number of comparisons needed, not counting the default case. */
Generate the code to test it and jump to the right place. */
void static bool
expand_case (gimple stmt) expand_switch_as_decision_tree_p (tree range,
unsigned int uniq ATTRIBUTE_UNUSED,
unsigned int count)
{ {
tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE; int max_ratio;
rtx default_label = 0;
struct case_node *n;
unsigned int count, uniq;
rtx index;
rtx table_label;
int ncases;
rtx *labelvec;
int i;
rtx before_case, end, lab;
tree index_expr = gimple_switch_index (stmt); /* If neither casesi or tablejump is available, or flag_jump_tables
tree index_type = TREE_TYPE (index_expr); over-ruled us, we really have no choice. */
int unsignedp = TYPE_UNSIGNED (index_type); if (!HAVE_casesi && !HAVE_tablejump)
return true;
/* The insn after which the case dispatch should finally if (!flag_jump_tables)
be emitted. Zero for a dummy. */ return true;
rtx start;
/* A list of case labels; it is first built as a list and it may then
be rearranged into a nearly balanced binary tree. */
struct case_node *case_list = 0;
/* Label to jump to if no case matches. */
tree default_label_decl = NULL_TREE;
alloc_pool case_node_pool = create_alloc_pool ("struct case_node pool",
sizeof (struct case_node),
100);
do_pending_stack_adjust ();
/* An ERROR_MARK occurs for various reasons including invalid data type. */
if (index_type != error_mark_node)
{
tree elt;
bitmap label_bitmap;
int stopi = 0;
/* cleanup_tree_cfg removes all SWITCH_EXPR with their index
expressions being INTEGER_CST. */
gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
/* The default case, if ever taken, is the first element. */
elt = gimple_switch_label (stmt, 0);
if (!CASE_LOW (elt) && !CASE_HIGH (elt))
{
default_label_decl = CASE_LABEL (elt);
stopi = 1;
}
for (i = gimple_switch_num_labels (stmt) - 1; i >= stopi; --i)
{
tree low, high;
elt = gimple_switch_label (stmt, i);
low = CASE_LOW (elt); /* If the switch is relatively small such that the cost of one
gcc_assert (low); indirect jump on the target are higher than the cost of a
high = CASE_HIGH (elt); decision tree, go with the decision tree.
/* The canonical from of a case label in GIMPLE is that a simple case If range of values is much bigger than number of values,
has an empty CASE_HIGH. For the casesi and tablejump expanders, or if it is too large to represent in a HOST_WIDE_INT,
the back ends want simple cases to have high == low. */ make a sequence of conditional branches instead of a dispatch.
gcc_assert (! high || tree_int_cst_lt (low, high));
if (! high)
high = low;
case_list = add_case_node (case_list, index_type, low, high, The definition of "much bigger" depends on whether we are
CASE_LABEL (elt), case_node_pool); optimizing for size or for speed. If the former, the maximum
} ratio range/count = 3, because this was found to be the optimal
ratio for size on i686-pc-linux-gnu, see PR11823. The ratio
10 is much older, and was probably selected after an extensive
benchmarking investigation on numerous platforms. Or maybe it
just made sense to someone at some point in the history of GCC,
who knows... */
max_ratio = optimize_insn_for_size_p () ? 3 : 10;
if (count < case_values_threshold ()
|| ! host_integerp (range, /*pos=*/1)
|| compare_tree_int (range, max_ratio * count) > 0)
return true;
return false;
}
before_case = start = get_last_insn (); /* Generate a decision tree, switching on INDEX_EXPR and jumping to
if (default_label_decl) one of the labels in CASE_LIST or to the DEFAULT_LABEL.
default_label = label_rtx (default_label_decl);
/* Get upper and lower bounds of case values. */ We generate a binary decision tree to select the appropriate target
code. This is done as follows:
uniq = 0; If the index is a short or char that we do not have
count = 0; an insn to handle comparisons directly, convert it to
label_bitmap = BITMAP_ALLOC (NULL); a full integer now, rather than letting each comparison
for (n = case_list; n; n = n->right) generate the conversion.
{
/* Count the elements and track the largest and smallest
of them (treating them as signed even if they are not). */
if (count++ == 0)
{
minval = n->low;
maxval = n->high;
}
else
{
if (tree_int_cst_lt (n->low, minval))
minval = n->low;
if (tree_int_cst_lt (maxval, n->high))
maxval = n->high;
}
/* A range counts double, since it requires two compares. */
if (! tree_int_cst_equal (n->low, n->high))
count++;
/* If we have not seen this label yet, then increase the Load the index into a register.
number of unique case node targets seen. */
lab = label_rtx (n->code_label);
if (bitmap_set_bit (label_bitmap, CODE_LABEL_NUMBER (lab)))
uniq++;
}
BITMAP_FREE (label_bitmap); The list of cases is rearranged into a binary tree,
nearly optimal assuming equal probability for each case.
/* cleanup_tree_cfg removes all SWITCH_EXPR with a single The tree is transformed into RTL, eliminating redundant
destination, such as one with a default case only. test conditions at the same time.
It also removes cases that are out of range for the switch
type, so we should never get a zero here. */
gcc_assert (count > 0);
/* Compute span of values. */ If program flow could reach the end of the decision tree
range = fold_build2 (MINUS_EXPR, index_type, maxval, minval); an unconditional jump to the default code is emitted.
/* If range of values is much bigger than number of values, The above process is unaware of the CFG. The caller has to fix up
make a sequence of conditional branches instead of a dispatch. the CFG itself. This is done in cfgexpand.c. */
If the switch-index is a constant, do it this way
because we can optimize it. */
if (count < case_values_threshold () static void
|| compare_tree_int (range, emit_case_decision_tree (tree index_expr, tree index_type,
(optimize_insn_for_size_p () ? 3 : 10) * count) > 0 struct case_node *case_list, rtx default_label)
/* RANGE may be signed, and really large ranges will show up {
as negative numbers. */ rtx index = expand_normal (index_expr);
|| compare_tree_int (range, 0) < 0
|| !flag_jump_tables
|| TREE_CONSTANT (index_expr)
/* If neither casesi or tablejump is available, we can
only go this way. */
|| (!HAVE_casesi && !HAVE_tablejump))
{
index = expand_normal (index_expr);
/* If the index is a short or char that we do not have
an insn to handle comparisons directly, convert it to
a full integer now, rather than letting each comparison
generate the conversion. */
if (GET_MODE_CLASS (GET_MODE (index)) == MODE_INT if (GET_MODE_CLASS (GET_MODE (index)) == MODE_INT
&& ! have_insn_for (COMPARE, GET_MODE (index))) && ! have_insn_for (COMPARE, GET_MODE (index)))
{ {
int unsignedp = TYPE_UNSIGNED (index_type);
enum machine_mode wider_mode; enum machine_mode wider_mode;
for (wider_mode = GET_MODE (index); wider_mode != VOIDmode; for (wider_mode = GET_MODE (index); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode)) wider_mode = GET_MODE_WIDER_MODE (wider_mode))
...@@ -1912,35 +1865,54 @@ expand_case (gimple stmt) ...@@ -1912,35 +1865,54 @@ expand_case (gimple stmt)
set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (index_expr), index); set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (index_expr), index);
} }
/* We generate a binary decision tree to select the balance_case_nodes (&case_list, NULL);
appropriate target code. This is done as follows:
The list of cases is rearranged into a binary tree,
nearly optimal assuming equal probability for each case.
The tree is transformed into RTL, eliminating
redundant test conditions at the same time.
If program flow could reach the end of the /* Don't want to include tree-pass.h here. This code will be moved
decision tree an unconditional jump to the to a GIMPLE pass for GCC 4.9 anyway, so for now always dump. */
default code is emitted. */ if (dump_file && 1/*(dump_flags & TDF_DETAILS)*/)
{
int indent_step = ceil_log2 (TYPE_PRECISION (index_type)) + 2;
fprintf (dump_file, ";; Expanding GIMPLE switch as decision tree:\n");
dump_case_nodes (dump_file, case_list, indent_step, 0);
}
balance_case_nodes (&case_list, NULL);
emit_case_nodes (index, case_list, default_label, index_type); emit_case_nodes (index, case_list, default_label, index_type);
if (default_label) if (default_label)
emit_jump (default_label); emit_jump (default_label);
} }
else
{ /* Generate a dispatch tabler, switching on INDEX_EXPR and jumping to
one of the labels in CASE_LIST or to the DEFAULT_LABEL.
MINVAL, MAXVAL, and RANGE are the extrema and range of the case
labels in CASE_LIST.
First, a jump insn is emitted. First we try "casesi". If that
fails, try "tablejump". A target *must* have one of them (or both).
Then, a table with the target labels is emitted.
The process is unaware of the CFG. The caller has to fix up
the CFG itself. This is done in cfgexpand.c. */
static void
emit_case_dispatch_table (tree index_expr, tree index_type,
struct case_node *case_list, rtx default_label,
tree minval, tree maxval, tree range)
{
int i, ncases;
struct case_node *n;
rtx *labelvec;
rtx fallback_label = label_rtx (case_list->code_label); rtx fallback_label = label_rtx (case_list->code_label);
table_label = gen_label_rtx (); rtx table_label = gen_label_rtx ();
if (! try_casesi (index_type, index_expr, minval, range, if (! try_casesi (index_type, index_expr, minval, range,
table_label, default_label, fallback_label)) table_label, default_label, fallback_label))
{ {
bool ok; bool ok;
/* Index jumptables from zero for suitable values of /* Index jumptables from zero for suitable values of minval to avoid
minval to avoid a subtraction. */ a subtraction. For the rationale see:
"http://gcc.gnu.org/ml/gcc-patches/2001-10/msg01234.html". */
if (optimize_insn_for_speed_p () if (optimize_insn_for_speed_p ()
&& compare_tree_int (minval, 0) > 0 && compare_tree_int (minval, 0) > 0
&& compare_tree_int (minval, 3) < 0) && compare_tree_int (minval, 3) < 0)
...@@ -2002,12 +1974,137 @@ expand_case (gimple stmt) ...@@ -2002,12 +1974,137 @@ expand_case (gimple stmt)
/* Record no drop-through after the table. */ /* Record no drop-through after the table. */
emit_barrier (); emit_barrier ();
}
/* Terminate a case (Pascal/Ada) or switch (C) statement
in which ORIG_INDEX is the expression to be tested.
If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
type as given in the source before any compiler conversions.
Generate the code to test it and jump to the right place. */
void
expand_case (gimple stmt)
{
tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
rtx default_label = NULL_RTX;
unsigned int count, uniq;
int i, stopi = 0;
rtx before_case, end;
int ncases = gimple_switch_num_labels (stmt);
tree index_expr = gimple_switch_index (stmt);
tree index_type = TREE_TYPE (index_expr);
tree elt;
bitmap label_bitmap;
/* The insn after which the case dispatch should finally
be emitted. Zero for a dummy. */
rtx start;
/* A list of case labels; it is first built as a list and it may then
be rearranged into a nearly balanced binary tree. */
struct case_node *case_list = 0;
/* A pool for case nodes. */
alloc_pool case_node_pool;
/* An ERROR_MARK occurs for various reasons including invalid data type.
??? Can this still happen, with GIMPLE and all? */
if (index_type == error_mark_node)
return;
/* cleanup_tree_cfg removes all SWITCH_EXPR with their index
expressions being INTEGER_CST. */
gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
case_node_pool = create_alloc_pool ("struct case_node pool",
sizeof (struct case_node),
100);
do_pending_stack_adjust ();
/* The default case, if ever taken, is the first element. */
elt = gimple_switch_label (stmt, 0);
if (!CASE_LOW (elt) && !CASE_HIGH (elt))
{
default_label = label_rtx (CASE_LABEL (elt));
stopi = 1;
}
/* Get upper and lower bounds of case values. */
elt = gimple_switch_label (stmt, stopi);
minval = fold_convert (index_type, CASE_LOW (elt));
elt = gimple_switch_label (stmt, ncases - 1);
if (CASE_HIGH (elt))
maxval = fold_convert (index_type, CASE_HIGH (elt));
else
maxval = fold_convert (index_type, CASE_LOW (elt));
/* Compute span of values. */
range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
/* Listify the labels queue and gather some numbers to decide
how to expand this switch(). */
uniq = 0;
count = 0;
label_bitmap = BITMAP_ALLOC (NULL);
for (i = gimple_switch_num_labels (stmt) - 1; i >= stopi; --i)
{
tree low, high;
rtx lab;
elt = gimple_switch_label (stmt, i);
low = CASE_LOW (elt);
gcc_assert (low);
high = CASE_HIGH (elt);
gcc_assert (! high || tree_int_cst_lt (low, high));
/* Count the elements.
A range counts double, since it requires two compares. */
count++;
if (high)
count++;
/* If we have not seen this label yet, then increase the
number of unique case node targets seen. */
lab = label_rtx (CASE_LABEL (elt));
if (bitmap_set_bit (label_bitmap, CODE_LABEL_NUMBER (lab)))
uniq++;
/* The canonical from of a case label in GIMPLE is that a simple case
has an empty CASE_HIGH. For the casesi and tablejump expanders,
the back ends want simple cases to have high == low. */
if (! high)
high = low;
case_list = add_case_node (case_list, index_type, low, high,
CASE_LABEL (elt), case_node_pool);
} }
BITMAP_FREE (label_bitmap);
/* cleanup_tree_cfg removes all SWITCH_EXPR with a single
destination, such as one with a default case only.
It also removes cases that are out of range for the switch
type, so we should never get a zero here. */
gcc_assert (count > 0);
before_case = start = get_last_insn ();
/* Decide how to expand this switch.
The two options at this point are a dispatch table (casesi or
tablejump) or a decision tree. */
if (expand_switch_as_decision_tree_p (range, uniq, count))
emit_case_decision_tree (index_expr, index_type,
case_list, default_label);
else
emit_case_dispatch_table (index_expr, index_type,
case_list, default_label,
minval, maxval, range);
before_case = NEXT_INSN (before_case); before_case = NEXT_INSN (before_case);
end = get_last_insn (); end = get_last_insn ();
reorder_insns (before_case, end, start); reorder_insns (before_case, end, start);
}
free_temp_slots (); free_temp_slots ();
free_alloc_pool (case_node_pool); free_alloc_pool (case_node_pool);
......
2012-07-05 Steven Bosscher <steven@gcc.gnu.org>
* gcc.c-torture/compile/20000326-1.c: Fix to not optimize to empty.
2012-07-05 Matthew Gretton-Dann <matthew.gretton-dann@arm.com> 2012-07-05 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* gcc.target/arm/fma-sp.c: New testcase. * gcc.target/arm/fma-sp.c: New testcase.
......
...@@ -2,22 +2,21 @@ long sys_reboot(int magic1, int magic2, int cmd, void * arg) ...@@ -2,22 +2,21 @@ long sys_reboot(int magic1, int magic2, int cmd, void * arg)
{ {
switch (cmd) { switch (cmd) {
case 0x89ABCDEF: case 0x89ABCDEF:
break; return 1;
case 0x00000000: case 0x00000000:
break; return 2;
case 0xCDEF0123: case 0xCDEF0123:
break; return 3;
case 0x4321FEDC: case 0x4321FEDC:
break; return 4;
case 0xA1B2C3D4: case 0xA1B2C3D4:
break; return 5;
default: default:
break;
};
return 0; return 0;
};
} }
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