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" } }

Reply via email to