stmt.c: Don't include insn-codes.h.

* stmt.c: Don't include insn-codes.h.
	(expand_end_case): Machine specific logic moved to expr.c.
	No need to worry about __builtin_classify_type.
	(check_for_full_enumeration_handling, emit_case_nodes):
	Kill #if 0 blocks.

	* builtins.o (expand_builtin_classify_type): Split up so code
	can be shared with fold_builtin_classify_type.
	(type_to_class, fold_builtin_classify_type): New functions.
	(fold_builtins): Handle __builtin_classify_type.

	* expr.c (do_tablejump): Now static.
	(case_values_threshold, try_casesi, try_tablejump): New;
	code mostly from stmt.c (expand_end_case).
	(expr.h): Update prototypes.

	* Makefile.in (stmt.o): Update dependencies.

From-SVN: r45078
This commit is contained in:
Zack Weinberg 2001-08-21 15:51:22 +00:00
parent 71038fd576
commit ad82abb8e6
6 changed files with 223 additions and 207 deletions

View File

@ -1,9 +1,29 @@
2001-08-21 Zack Weinberg <zackw@panix.com>
* stmt.c: Don't include insn-codes.h.
(expand_end_case): Machine specific logic moved to expr.c.
No need to worry about __builtin_classify_type.
(check_for_full_enumeration_handling, emit_case_nodes):
Kill #if 0 blocks.
* builtins.o (expand_builtin_classify_type): Split up so code
can be shared with fold_builtin_classify_type.
(type_to_class, fold_builtin_classify_type): New functions.
(fold_builtins): Handle __builtin_classify_type.
* expr.c (do_tablejump): Now static.
(case_values_threshold, try_casesi, try_tablejump): New;
code mostly from stmt.c (expand_end_case).
(expr.h): Update prototypes.
* Makefile.in (stmt.o): Update dependencies.
2001-08-21 Will Cohen <wcohen@redhat.com>
* configure/alpha/alpha.h (CONDITIONAL_REGISTER_USAGE): Added local
declaration of variable i.
* configure/rs6000/rs6000.h (CONDITIONAL_REGISTER_USAGE): Added local
declaration of variable i.
* configure/alpha/alpha.h (CONDITIONAL_REGISTER_USAGE): Added local
declaration of variable i.
* configure/rs6000/rs6000.h (CONDITIONAL_REGISTER_USAGE): Added local
declaration of variable i.
2001-08-21 Richard Henderson <rth@redhat.com>

View File

@ -1383,7 +1383,7 @@ function.o : function.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
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 \

View File

@ -91,6 +91,7 @@ static rtx expand_builtin_apply_args PARAMS ((void));
static rtx expand_builtin_apply_args_1 PARAMS ((void));
static rtx expand_builtin_apply PARAMS ((rtx, rtx, rtx));
static void expand_builtin_return PARAMS ((rtx));
static int type_to_class PARAMS ((tree));
static rtx expand_builtin_classify_type PARAMS ((tree));
static rtx expand_builtin_mathfn PARAMS ((tree, rtx, rtx));
static rtx expand_builtin_constant_p PARAMS ((tree));
@ -142,6 +143,7 @@ static rtx expand_builtin_fputs PARAMS ((tree, int));
static tree stabilize_va_list PARAMS ((tree, int));
static rtx expand_builtin_expect PARAMS ((tree, rtx));
static tree fold_builtin_constant_p PARAMS ((tree));
static tree fold_builtin_classify_type PARAMS ((tree));
static tree build_function_call_expr PARAMS ((tree, tree));
static int validate_arglist PARAMS ((tree, ...));
@ -1267,6 +1269,37 @@ expand_builtin_return (result)
expand_null_return ();
}
/* Used by expand_builtin_classify_type and fold_builtin_classify_type. */
static enum type_class
type_to_class (type)
tree type;
{
switch (TREE_CODE (type))
{
case VOID_TYPE: return void_type_class;
case INTEGER_TYPE: return integer_type_class;
case CHAR_TYPE: return char_type_class;
case ENUMERAL_TYPE: return enumeral_type_class;
case BOOLEAN_TYPE: return boolean_type_class;
case POINTER_TYPE: return pointer_type_class;
case REFERENCE_TYPE: return reference_type_class;
case OFFSET_TYPE: return offset_type_class;
case REAL_TYPE: return real_type_class;
case COMPLEX_TYPE: return complex_type_class;
case FUNCTION_TYPE: return function_type_class;
case METHOD_TYPE: return method_type_class;
case RECORD_TYPE: return record_type_class;
case UNION_TYPE:
case QUAL_UNION_TYPE: return union_type_class;
case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
? string_type_class : array_type_class);
case SET_TYPE: return set_type_class;
case FILE_TYPE: return file_type_class;
case LANG_TYPE: return lang_type_class;
default: return no_type_class;
}
}
/* Expand a call to __builtin_classify_type with arguments found in
ARGLIST. */
static rtx
@ -1274,51 +1307,7 @@ expand_builtin_classify_type (arglist)
tree arglist;
{
if (arglist != 0)
{
tree type = TREE_TYPE (TREE_VALUE (arglist));
enum tree_code code = TREE_CODE (type);
if (code == VOID_TYPE)
return GEN_INT (void_type_class);
if (code == INTEGER_TYPE)
return GEN_INT (integer_type_class);
if (code == CHAR_TYPE)
return GEN_INT (char_type_class);
if (code == ENUMERAL_TYPE)
return GEN_INT (enumeral_type_class);
if (code == BOOLEAN_TYPE)
return GEN_INT (boolean_type_class);
if (code == POINTER_TYPE)
return GEN_INT (pointer_type_class);
if (code == REFERENCE_TYPE)
return GEN_INT (reference_type_class);
if (code == OFFSET_TYPE)
return GEN_INT (offset_type_class);
if (code == REAL_TYPE)
return GEN_INT (real_type_class);
if (code == COMPLEX_TYPE)
return GEN_INT (complex_type_class);
if (code == FUNCTION_TYPE)
return GEN_INT (function_type_class);
if (code == METHOD_TYPE)
return GEN_INT (method_type_class);
if (code == RECORD_TYPE)
return GEN_INT (record_type_class);
if (code == UNION_TYPE || code == QUAL_UNION_TYPE)
return GEN_INT (union_type_class);
if (code == ARRAY_TYPE)
{
if (TYPE_STRING_FLAG (type))
return GEN_INT (string_type_class);
else
return GEN_INT (array_type_class);
}
if (code == SET_TYPE)
return GEN_INT (set_type_class);
if (code == FILE_TYPE)
return GEN_INT (file_type_class);
if (code == LANG_TYPE)
return GEN_INT (lang_type_class);
}
return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
return GEN_INT (no_type_class);
}
@ -3806,6 +3795,17 @@ fold_builtin_constant_p (arglist)
return 0;
}
/* Fold a call to __builtin_classify_type. */
static tree
fold_builtin_classify_type (arglist)
tree arglist;
{
if (arglist == 0)
return build_int_2 (no_type_class, 0);
return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
}
/* Used by constant folding to eliminate some builtin calls early. EXP is
the CALL_EXPR of a call to a builtin function. */
@ -3825,6 +3825,9 @@ fold_builtin (exp)
case BUILT_IN_CONSTANT_P:
return fold_builtin_constant_p (arglist);
case BUILT_IN_CLASSIFY_TYPE:
return fold_builtin_classify_type (arglist);
case BUILT_IN_STRLEN:
if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
{

View File

@ -177,6 +177,7 @@ static rtx do_store_flag PARAMS ((tree, rtx, enum machine_mode, int));
#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,112 @@ do_store_flag (exp, target, mode, only_cheap)
return target;
}
/* Generate a tablejump instruction (used for switch statements). */
#ifdef HAVE_tablejump
/* Stubs in case we haven't got a casesi insn. */
#ifndef HAVE_casesi
# define HAVE_casesi 0
# define gen_casesi(a, b, c, d, e) (0)
# define CODE_FOR_casesi CODE_FOR_nothing
#endif
/* INDEX is the value being switched on, with the lowest value
/* If the 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;
}
/* Attempt to generate a casesi instruction. Returns 1 if successful,
0 otherwise (i.e. if there is no casesi instruction). */
int
try_casesi (index_type, index_expr, minval, range,
table_label, default_label)
tree index_type, index_expr, minval, range;
rtx table_label ATTRIBUTE_UNUSED;
rtx 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;
}
/* 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 +10832,7 @@ do_store_flag (exp, target, mode, only_cheap)
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 +10894,31 @@ do_tablejump (index, mode, range, table_label, default_label)
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;
}

View File

@ -540,8 +540,14 @@ extern void do_compare_rtx_and_jump PARAMS ((rtx, rtx, enum rtx_code, int,
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. */

View File

@ -43,7 +43,6 @@ Boston, MA 02111-1307, USA. */
#include "except.h"
#include "function.h"
#include "insn-config.h"
#include "insn-codes.h"
#include "expr.h"
#include "libfuncs.h"
#include "hard-reg-set.h"
@ -5021,10 +5020,6 @@ check_for_full_enumeration_handling (type)
{
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 +5117,6 @@ check_for_full_enumeration_handling (type)
}
}
}
#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 +5134,7 @@ free_case_nodes (cn)
}
/* 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 +5263,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. */
@ -5309,12 +5272,6 @@ expand_end_case (orig_index)
|| flag_pic
#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)
|| (TREE_CODE (index_expr) == COMPOUND_EXPR
&& TREE_CODE (TREE_OPERAND (index_expr, 1)) == INTEGER_CST))
{
@ -5399,100 +5356,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 +6005,6 @@ emit_case_nodes (index, node, default_label, index_type)
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))
{