stmt.c (expand_case): Try to narrow the index type if it's larger than a word.
authorEric Botcazou <ebotcazou@adacore.com>
Thu, 25 Jul 2019 16:16:32 +0000 (16:16 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Thu, 25 Jul 2019 16:16:32 +0000 (16:16 +0000)
* stmt.c (expand_case): Try to narrow the index type if it's larger
than a word.  Tidy up.

From-SVN: r273805

gcc/ChangeLog
gcc/stmt.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/case_optimization3.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/case_optimization3.ads [new file with mode: 0644]

index 4196db2..336e9ee 100644 (file)
@@ -1,5 +1,10 @@
 2019-07-25  Eric Botcazou  <ebotcazou@adacore.com>
 
+       * stmt.c (expand_case): Try to narrow the index type if it's larger
+       than a word.  Tidy up.
+
+2019-07-25  Eric Botcazou  <ebotcazou@adacore.com>
+
        * cif-code.def (NEVER_CALL): New code.
        * ipa-inline.c (want_inline_small_function_p): Fix formatting issues.
        Set the failure to CIF_NEVER_CALL if the IPA count is zero.
index 040899e..17f43d1 100644 (file)
@@ -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 ();
index 4dad677..948acc0 100644 (file)
@@ -1,3 +1,7 @@
+2019-07-25  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gnat.dg/case_optimization3.ad[sb]: New test.
+
 2019-07-25  Martin Liska  <mliska@suse.cz
            Dominik Infuhr  <dominik.infuehr@theobroma-systems.com>
 
diff --git a/gcc/testsuite/gnat.dg/case_optimization3.adb b/gcc/testsuite/gnat.dg/case_optimization3.adb
new file mode 100644 (file)
index 0000000..6887f32
--- /dev/null
@@ -0,0 +1,25 @@
+-- { 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" } }
diff --git a/gcc/testsuite/gnat.dg/case_optimization3.ads b/gcc/testsuite/gnat.dg/case_optimization3.ads
new file mode 100644 (file)
index 0000000..3e3c769
--- /dev/null
@@ -0,0 +1,10 @@
+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;