This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

less use of optabs/insn-codes, 2/n


This patch relocates a lot of low-level gunk associated with emitting
jump tables for switch statements.  It was in stmt.c, now it's in expr.c.
That allows stmt.c not to need insn-codes.h.

I killed some ancient #if 0 blocks in stmt.c while I was at it.  They
have not been touched since 1997, and given the "-- rms" on one of 'em,
I suspect not for a long time before that.

Open question: should there be a general
is_call_to_builtin (expr, BUILT_IN_FOO) predicate?  I couldn't find any
other places where such a thing was wanted.

case_values_threshold should be a target hook, but that would just
clutter up this patch, and I'm not in the mood for another episode of
10-minutes-per-operation CVS hell.

Bootstrapped i686-linux.  That target defines both casesi and tablejump.
(I'm not sure why it needs casesi - something weird with PIC mode.)

zw

	* stmt.c (check_for_full_enumeration_handling, emit_case_nodes):
	Zap #if 0 blocks.
	(is_call_to_builtin_classify_type): New function.
	(expand_end_case): All low-level code to generate a casesi
	or a tablejump split out to routines in expr.c.
	* expr.c (do_tablejump): Make static and defined always.
	(case_values_threshold, try_casesi, try_tablejump): New functions,
	code formerly in stmt.c (expand_end_case).
	* expr.h: Prototype try_casesi, try_tablejump, case_values_threshold;
	not do_tablejump.

===================================================================
Index: Makefile.in
--- Makefile.in	2001/08/18 20:25:50	1.725
+++ Makefile.in	2001/08/18 21:29:52
@@ -1383,7 +1383,7 @@ function.o : function.c $(CONFIG_H) $(SY
    function.h insn-codes.h $(EXPR_H) libfuncs.h $(REGS_H) hard-reg-set.h \
    insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) $(TM_P_H)
 stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h  \
-   insn-config.h insn-codes.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \
+   insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \
    $(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H)
 except.o : except.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
    except.h function.h $(EXPR_H) libfuncs.h integrate.h \
===================================================================
Index: stmt.c
--- stmt.c	2001/08/18 19:59:45	1.210
+++ stmt.c	2001/08/18 21:30:14
@@ -5021,10 +5021,6 @@ check_for_full_enumeration_handling (typ
 {
   register struct case_node *n;
   register tree chain;
-#if 0  /* variable used by 'if 0'ed  code below.  */
-  register struct case_node **l;
-  int all_values = 1;
-#endif
 
   /* True iff the selector type is a numbered set mode.  */
   int sparseness = 0;
@@ -5122,28 +5118,6 @@ check_for_full_enumeration_handling (typ
 	      }
 	  }
       }
-
-#if 0
-  /* ??? This optimization is disabled because it causes valid programs to
-     fail.  ANSI C does not guarantee that an expression with enum type
-     will have a value that is the same as one of the enumeration literals.  */
-
-  /* If all values were found as case labels, make one of them the default
-     label.  Thus, this switch will never fall through.  We arbitrarily pick
-     the last one to make the default since this is likely the most
-     efficient choice.  */
-
-  if (all_values)
-    {
-      for (l = &case_stack->data.case_stmt.case_list;
-	   (*l)->right != 0;
-	   l = &(*l)->right)
-	;
-
-      case_stack->data.case_stmt.default_label = (*l)->code_label;
-      *l = 0;
-    }
-#endif /* 0 */
 }
 
 /* Free CN, and its children.  */
@@ -5161,6 +5135,24 @@ free_case_nodes (cn)
 }
 
 
+
+/* In the interest of readability.  */
+static inline int is_call_to_builtin_classify_type PARAMS ((tree));
+
+static inline int
+is_call_to_builtin_classify_type (expr)
+     tree expr;
+{
+  return
+    (TREE_CODE (expr) == CALL_EXPR
+     && TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
+     && TREE_CODE (TREE_OPERAND (TREE_OPERAND (expr, 0), 0)) == FUNCTION_DECL
+     && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (expr, 0), 0))
+	 == BUILT_IN_NORMAL)
+     && (DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (expr, 0), 0))
+	 == BUILT_IN_CLASSIFY_TYPE));
+}
+
 /* Terminate a case (Pascal) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
    Generate the code to test it and jump to the right place.  */
@@ -5289,18 +5281,7 @@ expand_end_case (orig_index)
 	 If the switch-index is a constant, do it this way
 	 because we can optimize it.  */
 
-#ifndef CASE_VALUES_THRESHOLD
-#ifdef HAVE_casesi
-#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
-#else
-      /* If machine does not have a case insn that compares the
-	 bounds, this means extra overhead for dispatch tables
-	 which raises the threshold for using them.  */
-#define CASE_VALUES_THRESHOLD 5
-#endif /* HAVE_casesi */
-#endif /* CASE_VALUES_THRESHOLD */
-
-      else if (count < CASE_VALUES_THRESHOLD
+      else if (count < case_values_threshold ()
 	       || compare_tree_int (range, 10 * count) > 0
 	       /* RANGE may be signed, and really large ranges will show up
 		  as negative numbers.  */
@@ -5310,11 +5291,7 @@ expand_end_case (orig_index)
 #endif
 	       || TREE_CODE (index_expr) == INTEGER_CST
 	       /* These will reduce to a constant.  */
-	       || (TREE_CODE (index_expr) == CALL_EXPR
-		   && TREE_CODE (TREE_OPERAND (index_expr, 0)) == ADDR_EXPR
-		   && TREE_CODE (TREE_OPERAND (TREE_OPERAND (index_expr, 0), 0)) == FUNCTION_DECL
-		   && DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (index_expr, 0), 0)) == BUILT_IN_NORMAL
-		   && DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (index_expr, 0), 0)) == BUILT_IN_CLASSIFY_TYPE)
+	       || is_call_to_builtin_classify_type (index_expr)
 	       || (TREE_CODE (index_expr) == COMPOUND_EXPR
 		   && TREE_CODE (TREE_OPERAND (index_expr, 1)) == INTEGER_CST))
 	{
@@ -5399,100 +5376,15 @@ expand_end_case (orig_index)
 	}
       else
 	{
-	  int win = 0;
-#ifdef HAVE_casesi
-	  if (HAVE_casesi)
-	    {
-	      enum machine_mode index_mode = SImode;
-	      int index_bits = GET_MODE_BITSIZE (index_mode);
-	      rtx op1, op2;
-	      enum machine_mode op_mode;
-
-	      /* Convert the index to SImode.  */
-	      if (GET_MODE_BITSIZE (TYPE_MODE (index_type))
-		  > GET_MODE_BITSIZE (index_mode))
-		{
-		  enum machine_mode omode = TYPE_MODE (index_type);
-		  rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
-
-		  /* We must handle the endpoints in the original mode.  */
-		  index_expr = build (MINUS_EXPR, index_type,
-				      index_expr, minval);
-		  minval = integer_zero_node;
-		  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
-		  emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
-					   omode, 1, 0, default_label);
-		  /* Now we can safely truncate.  */
-		  index = convert_to_mode (index_mode, index, 0);
-		}
-	      else
-		{
-		  if (TYPE_MODE (index_type) != index_mode)
-		    {
-		      index_expr = convert (type_for_size (index_bits, 0),
-					    index_expr);
-		      index_type = TREE_TYPE (index_expr);
-		    }
-
-		  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
-		}
-	      emit_queue ();
-	      index = protect_from_queue (index, 0);
-	      do_pending_stack_adjust ();
-
-	      op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
-	      if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate)
-		  (index, op_mode))
-		index = copy_to_mode_reg (op_mode, index);
-
-	      op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
-
-	      op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
-	      op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
-				   op1, TREE_UNSIGNED (TREE_TYPE (minval)));
-	      if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
-		  (op1, op_mode))
-		op1 = copy_to_mode_reg (op_mode, op1);
-
-	      op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
-
-	      op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
-	      op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
-				   op2, TREE_UNSIGNED (TREE_TYPE (range)));
-	      if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
-		  (op2, op_mode))
-		op2 = copy_to_mode_reg (op_mode, op2);
-
-	      emit_jump_insn (gen_casesi (index, op1, op2,
-					  table_label, default_label));
-	      win = 1;
-	    }
-#endif
-#ifdef HAVE_tablejump
-	  if (! win && HAVE_tablejump)
+	  if (! try_casesi (index_type, index_expr, minval, range,
+			    table_label, default_label))
 	    {
 	      index_type = thiscase->data.case_stmt.nominal_type;
-	      index_expr = fold (build (MINUS_EXPR, index_type,
-					convert (index_type, index_expr),
-					convert (index_type, minval)));
-	      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
-	      emit_queue ();
-	      index = protect_from_queue (index, 0);
-	      do_pending_stack_adjust ();
-
-	      do_tablejump (index, TYPE_MODE (index_type),
-			    convert_modes (TYPE_MODE (index_type),
-					   TYPE_MODE (TREE_TYPE (range)),
-					   expand_expr (range, NULL_RTX,
-							VOIDmode, 0),
-					   TREE_UNSIGNED (TREE_TYPE (range))),
-			    table_label, default_label);
-	      win = 1;
+	      if (! try_tablejump (index_type, index_expr, minval, range,
+				   table_label, default_label))
+		abort ();
 	    }
-#endif
-	  if (! win)
-	    abort ();
-
+	  
 	  /* Get table of labels to jump to, in order of case index.  */
 
 	  ncases = TREE_INT_CST_LOW (range) + 1;
@@ -6133,20 +6025,6 @@ emit_case_nodes (index, node, default_la
       else if (node->right == 0 && node->left != 0)
 	{
 	  /* Just one subtree, on the left.  */
-
-#if 0 /* The following code and comment were formerly part
-	 of the condition here, but they didn't work
-	 and I don't understand what the idea was.  -- rms.  */
-	  /* If our "most probable entry" is less probable
-	     than the default label, emit a jump to
-	     the default label using condition codes
-	     already lying around.  With no right branch,
-	     a branch-greater-than will get us to the default
-	     label correctly.  */
-	  if (use_cost_table
-	      && COST_TABLE (TREE_INT_CST_LOW (node->high)) < 12)
-	    ;
-#endif /* 0 */
 	  if (node->left->left || node->left->right
 	      || !tree_int_cst_equal (node->left->low, node->left->high))
 	    {
===================================================================
Index: expr.c
--- expr.c	2001/08/18 19:59:43	1.347
+++ expr.c	2001/08/18 21:30:53
@@ -177,6 +177,7 @@ static rtx do_store_flag	PARAMS ((tree, 
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
 #endif
+static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -10717,11 +10718,108 @@ do_store_flag (exp, target, mode, only_c
   return target;
 }
 
-/* Generate a tablejump instruction (used for switch statements).  */
+/* Attempt to generate a casesi instruction.  Returns 1 if successful,
+   0 otherwise (i.e. if there is no casesi instruction).  */
 
-#ifdef HAVE_tablejump
+#ifndef HAVE_casesi
+#define HAVE_casesi 0
+#endif
+
+/* If machine does not have a case insn that compares the
+   bounds, this means extra overhead for dispatch tables
+   which raises the threshold for using them.  */
+#ifndef CASE_VALUES_THRESHOLD
+#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
+#endif /* CASE_VALUES_THRESHOLD */
+
+unsigned int
+case_values_threshold ()
+{
+  return CASE_VALUES_THRESHOLD;
+}
+
+int
+try_casesi (index_type, index_expr, minval, range,
+	    table_label, default_label)
+     tree index_type, index_expr, minval, range;
+     rtx table_label, default_label;
+{
+  enum machine_mode index_mode = SImode;
+  int index_bits = GET_MODE_BITSIZE (index_mode);
+  rtx op1, op2, index;
+  enum machine_mode op_mode;
+
+  if (! HAVE_casesi)
+    return 0;
+
+  /* Convert the index to SImode.  */
+  if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
+    {
+      enum machine_mode omode = TYPE_MODE (index_type);
+      rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+      /* We must handle the endpoints in the original mode.  */
+      index_expr = build (MINUS_EXPR, index_type,
+			  index_expr, minval);
+      minval = integer_zero_node;
+      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
+			       omode, 1, 0, default_label);
+      /* Now we can safely truncate.  */
+      index = convert_to_mode (index_mode, index, 0);
+    }
+  else
+    {
+      if (TYPE_MODE (index_type) != index_mode)
+	{
+	  index_expr = convert (type_for_size (index_bits, 0),
+				index_expr);
+	  index_type = TREE_TYPE (index_expr);
+	}
+
+      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+    }
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate)
+      (index, op_mode))
+    index = copy_to_mode_reg (op_mode, index);
+
+  op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
+  op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
+		       op1, TREE_UNSIGNED (TREE_TYPE (minval)));
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
+      (op1, op_mode))
+    op1 = copy_to_mode_reg (op_mode, op1);
+
+  op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
+  op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
+		       op2, TREE_UNSIGNED (TREE_TYPE (range)));
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
+      (op2, op_mode))
+    op2 = copy_to_mode_reg (op_mode, op2);
+
+  emit_jump_insn (gen_casesi (index, op1, op2,
+			      table_label, default_label));
+  return 1;
+}
 
-/* INDEX is the value being switched on, with the lowest value
+/* Attempt to generate a tablejump instruction; same concept.  */
+#ifndef HAVE_tablejump
+#define HAVE_tablejump 0
+#define gen_tablejump(x, y) (0)
+#endif
+
+/* Subroutine of the next function.
+
+   INDEX is the value being switched on, with the lowest value
    in the table already subtracted.
    MODE is its expected mode (needed if INDEX is constant).
    RANGE is the length of the jump table.
@@ -10730,7 +10828,7 @@ do_store_flag (exp, target, mode, only_c
    DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
    index value is out of range.  */
 
-void
+static void
 do_tablejump (index, mode, range, table_label, default_label)
      rtx index, range, table_label, default_label;
      enum machine_mode mode;
@@ -10792,4 +10890,31 @@ do_tablejump (index, mode, range, table_
     emit_barrier ();
 }
 
-#endif /* HAVE_tablejump  */
+int
+try_tablejump (index_type, index_expr, minval, range,
+	       table_label, default_label)
+     tree index_type, index_expr, minval, range;
+     rtx table_label, default_label;
+{
+  rtx index;
+
+  if (! HAVE_tablejump)
+    return 0;
+
+  index_expr = fold (build (MINUS_EXPR, index_type,
+			    convert (index_type, index_expr),
+			    convert (index_type, minval)));
+  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  do_tablejump (index, TYPE_MODE (index_type),
+		convert_modes (TYPE_MODE (index_type),
+			       TYPE_MODE (TREE_TYPE (range)),
+			       expand_expr (range, NULL_RTX,
+					    VOIDmode, 0),
+			       TREE_UNSIGNED (TREE_TYPE (range))),
+		table_label, default_label);
+  return 1;
+}
===================================================================
Index: expr.h
--- expr.h	2001/08/18 19:59:44	1.89
+++ expr.h	2001/08/18 21:30:55
@@ -540,8 +540,14 @@ extern void do_compare_rtx_and_jump PARA
 					     enum machine_mode, rtx,
 					     unsigned int, rtx, rtx));
 
-/* Generate a tablejump instruction (used for switch statements).  */
-extern void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
+/* Two different ways of generating switch statements.  */
+extern int try_casesi    PARAMS ((tree, tree, tree, tree, rtx, rtx));
+extern int try_tablejump PARAMS ((tree, tree, tree, tree, rtx, rtx));
+
+/* Smallest number of adjacent cases before we use a jump table.
+   XXX Should be a target hook.  */
+extern unsigned int case_values_threshold PARAMS ((void));
+
 
 #ifdef TREE_CODE
 /* rtl.h and tree.h were included.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]