Add simple narrowing optimization to expand_case

Message ID 2959597.B64FfaS6ZD@arcturus.home
State New
Headers show
Series
  • Add simple narrowing optimization to expand_case
Related show

Commit Message

Eric Botcazou July 24, 2019, 9:57 a.m.
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  <ebotcazou@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  <ebotcazou@adacore.com>

	* gnat.dg/case_optimization3.ad[sb]: New test.

-- 
Eric Botcazou

Comments

Jeff Law July 24, 2019, 6:38 p.m. | #1
On 7/24/19 3:57 AM, Eric Botcazou wrote:
> 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  <ebotcazou@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  <ebotcazou@adacore.com>

> 

> 	* gnat.dg/case_optimization3.ad[sb]: New test.

> 

I wouldn't much care about dragging in libgcc for a -O0 build.  Instead
I'd pitch this as generating sensible code regardless of the
optimization level.

OK by me.

Jeff

Patch

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 ();