Hi,
this adds a simple narrowing optimization to expand_case in order to avoid
calling a double-word comparison routine when it is unnecessary to do so.
This is mainly for -O0 because the optimization is otherwise done by forward
propagation and avoids having to drag libgcc or not depending on the -O level.
Tested on x86_64-suse-linux, OK for the mainline?
2019-07-24 Eric Botcazou <ebotca...@adacore.com>
* stmt.c (expand_case): Try to narrow the index type if it's larger
than a word. Tidy up.
2019-07-24 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/case_optimization3.ad[sb]: New test.
--
Eric Botcazou
Index: stmt.c
===================================================================
--- stmt.c (revision 273480)
+++ stmt.c (working copy)
@@ -885,6 +885,7 @@ expand_case (gswitch *stmt)
tree index_type = TREE_TYPE (index_expr);
tree elt;
basic_block bb = gimple_bb (stmt);
+ gimple *def_stmt;
auto_vec<simple_case_node> case_list;
@@ -918,6 +919,31 @@ expand_case (gswitch *stmt)
else
maxval = fold_convert (index_type, CASE_LOW (elt));
+ /* Try to narrow the index type if it's larger than a word.
+ That is mainly for -O0 where an equivalent optimization
+ done by forward propagation is not run and is aimed at
+ avoiding a call to a comparison routine of libgcc. */
+ if (TYPE_PRECISION (index_type) > BITS_PER_WORD
+ && TREE_CODE (index_expr) == SSA_NAME
+ && (def_stmt = SSA_NAME_DEF_STMT (index_expr))
+ && is_gimple_assign (def_stmt)
+ && gimple_assign_rhs_code (def_stmt) == NOP_EXPR)
+ {
+ tree inner_index_expr = gimple_assign_rhs1 (def_stmt);
+ tree inner_index_type = TREE_TYPE (inner_index_expr);
+
+ if (INTEGRAL_TYPE_P (inner_index_type)
+ && TYPE_PRECISION (inner_index_type) <= BITS_PER_WORD
+ && int_fits_type_p (minval, inner_index_type)
+ && int_fits_type_p (maxval, inner_index_type))
+ {
+ index_expr = inner_index_expr;
+ index_type = inner_index_type;
+ minval = fold_convert (index_type, minval);
+ maxval = fold_convert (index_type, maxval);
+ }
+ }
+
/* Compute span of values. */
range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
@@ -969,27 +995,22 @@ expand_case (gswitch *stmt)
rtx_insn *before_case = 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 the default case is unreachable, then set default_label to NULL
+ so that we omit the range check when generating the dispatch table.
+ We also remove the edge to the unreachable default case. The block
+ itself will be automatically removed later. */
+ if (EDGE_COUNT (default_edge->dest->succs) == 0
+ && gimple_seq_unreachable_p (bb_seq (default_edge->dest)))
{
- /* If the default case is unreachable, then set default_label to NULL
- so that we omit the range check when generating the dispatch table.
- We also remove the edge to the unreachable default case. The block
- itself will be automatically removed later. */
- if (EDGE_COUNT (default_edge->dest->succs) == 0
- && gimple_seq_unreachable_p (bb_seq (default_edge->dest)))
- {
- default_label = NULL;
- remove_edge (default_edge);
- default_edge = NULL;
- }
- emit_case_dispatch_table (index_expr, index_type,
- case_list, default_label, default_edge,
- minval, maxval, range, bb);
+ default_label = NULL;
+ remove_edge (default_edge);
+ default_edge = NULL;
}
+ emit_case_dispatch_table (index_expr, index_type,
+ case_list, default_label, default_edge,
+ minval, maxval, range, bb);
+
reorder_insns (NEXT_INSN (before_case), get_last_insn (), before_case);
free_temp_slots ();
package Case_Optimization3 is
type T_UINT32 is range 0 .. (2 ** 32) - 1;
for T_UINT32'Size use 32;
subtype T_RANGE is T_UINT32 range 0 .. 7;
procedure Proc (Val : T_RANGE);
end Case_Optimization3;
-- { dg-do compile }
package body Case_Optimization3 is
procedure Proc (Val : T_RANGE) is
begin
case Val is
when 0 =>
raise Program_Error;
when 1 =>
null;
when 2 =>
null;
when 3 =>
null;
when 4 =>
null;
when others =>
null;
end case;
end;
end Case_Optimization3;
-- { dg-final { scan-assembler-not "__ucmpdi2" } }