/* Expands front end tree to back end RTL for GCC
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "rtl.h"
+#include "hard-reg-set.h"
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
#include "insn-config.h"
#include "expr.h"
#include "libfuncs.h"
-#include "hard-reg-set.h"
-#include "loop.h"
#include "recog.h"
#include "machmode.h"
#include "toplev.h"
static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree);
static void expand_null_return_1 (void);
-static rtx shift_return_value (rtx);
static void expand_value_return (rtx);
static void do_jump_if_equal (rtx, rtx, rtx, int);
static int estimate_case_costs (case_node_ptr);
static int node_has_high_bound (case_node_ptr, tree);
static int node_is_bounded (case_node_ptr, tree);
static void emit_case_nodes (rtx, case_node_ptr, rtx, tree);
-static struct case_node *add_case_node (struct case_node *, tree, tree, tree);
+static struct case_node *add_case_node (struct case_node *, tree,
+ tree, tree, tree);
\f
/* Return the rtx-label that corresponds to a LABEL_DECL,
rtx
label_rtx (tree label)
{
- if (TREE_CODE (label) != LABEL_DECL)
- abort ();
+ gcc_assert (TREE_CODE (label) == LABEL_DECL);
if (!DECL_RTL_SET_P (label))
{
tree function = decl_function_context (label);
struct function *p;
- if (!function)
- abort ();
+ gcc_assert (function);
if (function != current_function_decl)
p = find_function_data (function);
/* Check for a nonlocal goto to a containing function. Should have
gotten translated to __builtin_nonlocal_goto. */
tree context = decl_function_context (label);
- if (context != 0 && context != current_function_decl)
- abort ();
+ gcc_assert (!context || context == current_function_decl);
#endif
emit_jump (label_rtx (label));
or an ADDR_EXPR containing a STRING_CST. VOL nonzero means the
insn is volatile; don't optimize it. */
-void
+static void
expand_asm (tree string, int vol)
{
rtx body;
if (TREE_CODE (string) == ADDR_EXPR)
string = TREE_OPERAND (string, 0);
- body = gen_rtx_ASM_INPUT (VOIDmode, TREE_STRING_POINTER (string));
+ body = gen_rtx_ASM_INPUT (VOIDmode,
+ ggc_strdup (TREE_STRING_POINTER (string)));
MEM_VOLATILE_P (body) = vol;
message. */
if (!p)
{
- error ("output operand constraint lacks `='");
+ error ("output operand constraint lacks %<=%>");
return false;
}
*is_inout = (*p == '+');
/* Canonicalize the output constraint so that it begins with `='. */
- if (p != constraint || is_inout)
+ if (p != constraint || *is_inout)
{
char *buf;
size_t c_len = strlen (constraint);
if (p != constraint)
- warning ("output constraint `%c' for operand %d is not at the beginning",
+ warning (0, "output constraint %qc for operand %d "
+ "is not at the beginning",
*p, operand_num);
/* Make a copy of the constraint. */
{
case '+':
case '=':
- error ("operand constraint contains incorrectly positioned '+' or '='");
+ error ("operand constraint contains incorrectly positioned "
+ "%<+%> or %<=%>");
return false;
case '%':
if (operand_num + 1 == ninputs + noutputs)
{
- error ("`%%' constraint used with last operand");
+ error ("%<%%%> constraint used with last operand");
return false;
}
break;
case '+': case '=': case '&':
if (constraint == orig_constraint)
{
- error ("input operand constraint contains `%c'", constraint[j]);
+ error ("input operand constraint contains %qc", constraint[j]);
return false;
}
break;
if (constraint == orig_constraint
&& input_num + 1 == ninputs - ninout)
{
- error ("`%%' constraint used with last operand");
+ error ("%<%%%> constraint used with last operand");
return false;
}
break;
default:
if (! ISALPHA (constraint[j]))
{
- error ("invalid punctuation `%c' in constraint", constraint[j]);
+ error ("invalid punctuation %qc in constraint", constraint[j]);
return false;
}
if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
}
if (saw_match && !*allows_reg)
- warning ("matching constraint does not allow a register");
+ warning (0, "matching constraint does not allow a register");
return true;
}
-/* INPUT is one of the input operands from EXPR, an ASM_EXPR. Returns true
- if it is an operand which must be passed in memory (i.e. an "m"
- constraint), false otherwise. */
+/* Return true iff there's an overlap between REGS and DECL, where DECL
+ can be an asm-declared register. */
bool
-asm_op_is_mem_input (tree input, tree expr)
+decl_overlaps_hard_reg_set_p (tree decl, const HARD_REG_SET regs)
{
- const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (input)));
- tree outputs = ASM_OUTPUTS (expr);
- int noutputs = list_length (outputs);
- const char **constraints
- = (const char **) alloca ((noutputs) * sizeof (const char *));
- int i = 0;
- bool allows_mem, allows_reg;
- tree t;
+ if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
+ && DECL_REGISTER (decl)
+ && REG_P (DECL_RTL (decl))
+ && REGNO (DECL_RTL (decl)) < FIRST_PSEUDO_REGISTER)
+ {
+ rtx reg = DECL_RTL (decl);
+ unsigned int regno;
- /* Collect output constraints. */
- for (t = outputs; t ; t = TREE_CHAIN (t), i++)
- constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+ for (regno = REGNO (reg);
+ regno < (REGNO (reg)
+ + hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]);
+ regno++)
+ if (TEST_HARD_REG_BIT (regs, regno))
+ return true;
+ }
- /* We pass 0 for input_num, ninputs and ninout; they are only used for
- error checking which will be done at expand time. */
- parse_input_constraint (&constraint, 0, 0, noutputs, 0, constraints,
- &allows_mem, &allows_reg);
- return (!allows_reg && allows_mem);
+ return false;
}
+
/* Check for overlap between registers marked in CLOBBERED_REGS and
anything inappropriate in DECL. Emit error and return TRUE for error,
FALSE for ok. */
{
/* Conflicts between asm-declared register variables and the clobber
list are not allowed. */
- if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
- && DECL_REGISTER (decl)
- && REG_P (DECL_RTL (decl))
- && REGNO (DECL_RTL (decl)) < FIRST_PSEUDO_REGISTER)
+ if (decl_overlaps_hard_reg_set_p (decl, clobbered_regs))
{
- rtx reg = DECL_RTL (decl);
- unsigned int regno;
-
- for (regno = REGNO (reg);
- regno < (REGNO (reg)
- + hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]);
- regno++)
- if (TEST_HARD_REG_BIT (clobbered_regs, regno))
- {
- error ("asm-specifier for variable `%s' conflicts with asm clobber list",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ error ("asm-specifier for variable %qs conflicts with asm clobber list",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
- /* Reset registerness to stop multiple errors emitted for a
- single variable. */
- DECL_REGISTER (decl) = 0;
- return true;
- }
+ /* Reset registerness to stop multiple errors emitted for a single
+ variable. */
+ DECL_REGISTER (decl) = 0;
+ return true;
}
+
return false;
}
VOL nonzero means the insn is volatile; don't optimize it. */
-void
+static void
expand_asm_operands (tree string, tree outputs, tree inputs,
tree clobbers, int vol, location_t locus)
{
Case in point is when the i386 backend moved from cc0 to a hard reg --
maintaining source-level compatibility means automatically clobbering
the flags register. */
- clobbers = targetm.md_asm_clobbers (clobbers);
+ clobbers = targetm.md_asm_clobbers (outputs, inputs, clobbers);
/* Count the number of meaningful clobbered registers, ignoring what
we would ignore later. */
if (i >= 0 || i == -4)
++nclobbers;
else if (i == -2)
- error ("unknown register name `%s' in `asm'", regname);
+ error ("unknown register name %qs in %<asm%>", regname);
/* Mark clobbered registers. */
if (i >= 0)
{
- /* Clobbering the PIC register is an error */
+ /* Clobbering the PIC register is an error. */
if (i == (int) PIC_OFFSET_TABLE_REGNUM)
{
- error ("PIC register `%s' clobbered in `asm'", regname);
+ error ("PIC register %qs clobbered in %<asm%>", regname);
return;
}
ninputs += ninout;
if (ninputs + noutputs > MAX_RECOG_OPERANDS)
{
- error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
+ error ("more than %d operands in %<asm%>", MAX_RECOG_OPERANDS);
return;
}
bool allows_reg;
bool allows_mem;
rtx op;
+ bool ok;
- if (!parse_output_constraint (&constraints[i], i, ninputs,
+ ok = parse_output_constraint (&constraints[i], i, ninputs,
noutputs, &allows_mem, &allows_reg,
- &is_inout))
- abort ();
+ &is_inout);
+ gcc_assert (ok);
/* If an output operand is not a decl or indirect ref and our constraint
allows a register, make a temporary to act as an intermediate.
body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
: GET_MODE (output_rtx[0])),
- TREE_STRING_POINTER (string),
+ ggc_strdup (TREE_STRING_POINTER (string)),
empty_string, 0, argvec, constraintvec,
locus);
const char *constraint;
tree val, type;
rtx op;
+ bool ok;
constraint = constraints[i + noutputs];
- if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
- constraints, &allows_mem, &allows_reg))
- abort ();
+ ok = parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+ constraints, &allows_mem, &allows_reg);
+ gcc_assert (ok);
generating_concat_p = 0;
if (asm_operand_ok (op, constraint) <= 0)
{
- if (allows_reg)
+ if (allows_reg && TYPE_MODE (type) != BLKmode)
op = force_reg (TYPE_MODE (type), op);
else if (!allows_mem)
- warning ("asm operand %d probably doesn't match constraints",
+ warning (0, "asm operand %d probably doesn%'t match constraints",
i + noutputs);
else if (MEM_P (op))
{
}
else
{
- warning ("use of memory input without lvalue in "
+ warning (0, "use of memory input without lvalue in "
"asm operand %d is deprecated", i + noutputs);
if (CONSTANT_P (op))
ASM_OPERANDS_INPUT (body, i) = op;
ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
- = gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
+ = gen_rtx_ASM_INPUT (TYPE_MODE (type),
+ ggc_strdup (constraints[i + noutputs]));
if (decl_conflicts_with_clobbers_p (val, clobbered_regs))
clobber_conflict_found = 1;
if (noutputs == 1 && nclobbers == 0)
{
- ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]);
emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
}
output_rtx[i],
gen_rtx_ASM_OPERANDS
(GET_MODE (output_rtx[i]),
- TREE_STRING_POINTER (string),
- constraints[i], i, argvec, constraintvec,
- locus));
+ ggc_strdup (TREE_STRING_POINTER (string)),
+ ggc_strdup (constraints[i]),
+ i, argvec, constraintvec, locus));
MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
}
{
if (o[i] != TREE_VALUE (tail))
{
- expand_assignment (o[i], TREE_VALUE (tail), 0);
+ expand_assignment (o[i], TREE_VALUE (tail));
free_temp_slots ();
/* Restore the original value so that it's correct the next
if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
{
- error ("too many alternatives in `asm'");
+ error ("too many alternatives in %<asm%>");
return false;
}
if (n_occurrences (',', constraint) != nalternatives)
{
- error ("operand constraints for `asm' differ in number of alternatives");
+ error ("operand constraints for %<asm%> differ "
+ "in number of alternatives");
return false;
}
return true;
failure:
- error ("duplicate asm operand name '%s'",
+ error ("duplicate asm operand name %qs",
TREE_STRING_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
return false;
}
}
*q = '\0';
- error ("undefined named operand '%s'", p + 1);
+ error ("undefined named operand %qs", p + 1);
op = 0;
found:
p = strchr (p, '\0');
/* Verify the no extra buffer space assumption. */
- if (p > q)
- abort ();
+ gcc_assert (p <= q);
/* Shift the rest of the buffer down to fill the gap. */
memmove (p, q + 1, strlen (q + 1) + 1);
default:
/* Referencing a volatile value is a side effect, so don't warn. */
- if ((DECL_P (exp)
- || TREE_CODE_CLASS (TREE_CODE (exp)) == 'r')
+ if ((DECL_P (exp) || REFERENCE_CLASS_P (exp))
&& TREE_THIS_VOLATILE (exp))
return 0;
/* If this is an expression which has no operands, there is no value
to be unused. There are no such language-independent codes,
but front ends may define such. */
- if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'e'
- && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
+ if (EXPRESSION_CLASS_P (exp) && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
return 0;
maybe_warn:
if (TREE_SIDE_EFFECTS (exp))
return 0;
- warning ("%Hvalue computed is not used", &locus);
+ warning (0, "%Hvalue computed is not used", &locus);
return 1;
}
}
-\f
-/* Return nonzero if we should preserve sub-expressions as separate
- pseudos. We never do so if we aren't optimizing. We always do so
- if -fexpensive-optimizations. */
-
-int
-preserve_subexpressions_p (void)
-{
- return optimize && (cfun || flag_expensive_optimizations);
-}
\f
/* Generate RTL to return from the current function, with no value.
emit_jump (end_label);
}
-/* If the current function returns values in the most significant part
- of a register, shift return value VAL appropriately. The mode of
- the function's return type is known not to be BLKmode. */
-
-static rtx
-shift_return_value (rtx val)
-{
- tree type;
-
- type = TREE_TYPE (DECL_RESULT (current_function_decl));
- if (targetm.calls.return_in_msb (type))
- {
- rtx target;
- HOST_WIDE_INT shift;
-
- target = DECL_RTL (DECL_RESULT (current_function_decl));
- shift = (GET_MODE_BITSIZE (GET_MODE (target))
- - BITS_PER_UNIT * int_size_in_bytes (type));
- if (shift > 0)
- val = expand_shift (LSHIFT_EXPR, GET_MODE (target),
- gen_lowpart (GET_MODE (target), val),
- build_int_cst (NULL_TREE, shift, 0), target, 1);
- }
- return val;
-}
-
-
/* Generate RTL to return from the current function, with value VAL. */
static void
static void
expand_null_return_1 (void)
{
- rtx end_label;
-
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
-
- end_label = return_label;
- if (end_label == 0)
- end_label = return_label = gen_label_rtx ();
- emit_jump (end_label);
+ emit_jump (return_label);
}
\f
/* Generate RTL to evaluate the expression RETVAL and return it
if (GET_MODE_SIZE (tmpmode) >= bytes)
break;
- /* No suitable mode found. */
- if (tmpmode == VOIDmode)
- abort ();
+ /* A suitable mode should have been found. */
+ gcc_assert (tmpmode != VOIDmode);
PUT_MODE (result_rtl, tmpmode);
}
val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val);
/* Return the calculated value. */
- expand_value_return (shift_return_value (val));
+ expand_value_return (val);
}
else
{
mark_reg_pointer (DECL_RTL (decl),
TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
}
-
- maybe_set_unchanging (DECL_RTL (decl), decl);
}
else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
to the proper address. */
if (DECL_RTL_SET_P (decl))
{
- if (!MEM_P (DECL_RTL (decl))
- || !REG_P (XEXP (DECL_RTL (decl), 0)))
- abort ();
+ gcc_assert (MEM_P (DECL_RTL (decl)));
+ gcc_assert (REG_P (XEXP (DECL_RTL (decl), 0)));
oldaddr = XEXP (DECL_RTL (decl), 0);
}
emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX);
}
\f
-/* Emit code to perform the initialization of a declaration DECL. */
-
-void
-expand_decl_init (tree decl)
-{
- int was_used = TREE_USED (decl);
-
- /* If this is a CONST_DECL, we don't have to generate any code. Likewise
- for static decls. */
- if (TREE_CODE (decl) == CONST_DECL
- || TREE_STATIC (decl))
- return;
-
- /* Compute and store the initial value now. */
-
- push_temp_slots ();
-
- if (DECL_INITIAL (decl) == error_mark_node)
- {
- enum tree_code code = TREE_CODE (TREE_TYPE (decl));
-
- if (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
- || code == POINTER_TYPE || code == REFERENCE_TYPE)
- expand_assignment (decl, convert (TREE_TYPE (decl), integer_zero_node),
- 0);
- }
- else if (DECL_INITIAL (decl) && TREE_CODE (DECL_INITIAL (decl)) != TREE_LIST)
- {
- emit_line_note (DECL_SOURCE_LOCATION (decl));
- expand_assignment (decl, DECL_INITIAL (decl), 0);
- }
-
- /* Don't let the initialization count as "using" the variable. */
- TREE_USED (decl) = was_used;
-
- /* Free any temporaries we made while initializing the decl. */
- preserve_temp_slots (NULL_RTX);
- free_temp_slots ();
- pop_temp_slots ();
-}
-
-\f
/* DECL is an anonymous union. CLEANUP is a cleanup for DECL.
DECL_ELTS is the list of elements that belong to DECL's type.
In each, the TREE_VALUE is a VAR_DECL, and the TREE_PURPOSE a cleanup. */
{
tree decl_elt = TREE_VALUE (t);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
+ rtx decl_rtl;
/* If any of the elements are addressable, so is the entire
union. */
DECL_MODE (decl_elt) = mode
= mode_for_size_tree (DECL_SIZE (decl_elt), MODE_INT, 1);
- /* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
- instead create a new MEM rtx with the proper mode. */
- if (MEM_P (x))
- {
- if (mode == GET_MODE (x))
- SET_DECL_RTL (decl_elt, x);
- else
- SET_DECL_RTL (decl_elt, adjust_address_nv (x, mode, 0));
- }
- else if (REG_P (x))
+ if (mode == GET_MODE (x))
+ decl_rtl = x;
+ else if (MEM_P (x))
+ /* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
+ instead create a new MEM rtx with the proper mode. */
+ decl_rtl = adjust_address_nv (x, mode, 0);
+ else
{
- if (mode == GET_MODE (x))
- SET_DECL_RTL (decl_elt, x);
- else
- SET_DECL_RTL (decl_elt, gen_lowpart_SUBREG (mode, x));
+ gcc_assert (REG_P (x));
+ decl_rtl = gen_lowpart_SUBREG (mode, x);
}
- else
- abort ();
+ SET_DECL_RTL (decl_elt, decl_rtl);
}
}
\f
/* Do the insertion of a case label into case_list. The labels are
fed to us in descending order from the sorted vector of case labels used
in the tree part of the middle end. So the list we construct is
- sorted in ascending order. */
+ sorted in ascending order. The bounds on the case range, LOW and HIGH,
+ are converted to case's index type TYPE. */
-struct case_node *
-add_case_node (struct case_node *head, tree low, tree high, tree label)
+static struct case_node *
+add_case_node (struct case_node *head, tree type, tree low, tree high,
+ tree label)
{
+ tree min_value, max_value;
struct case_node *r;
+ gcc_assert (TREE_CODE (low) == INTEGER_CST);
+ gcc_assert (!high || TREE_CODE (high) == INTEGER_CST);
+
+ min_value = TYPE_MIN_VALUE (type);
+ max_value = TYPE_MAX_VALUE (type);
+
/* If there's no HIGH value, then this is not a case range; it's
just a simple case label. But that's just a degenerate case
range.
If the bounds are equal, turn this into the one-value case. */
if (!high || tree_int_cst_equal (low, high))
- high = low;
+ {
+ /* If the simple case value is unreachable, ignore it. */
+ if ((TREE_CODE (min_value) == INTEGER_CST
+ && tree_int_cst_compare (low, min_value) < 0)
+ || (TREE_CODE (max_value) == INTEGER_CST
+ && tree_int_cst_compare (low, max_value) > 0))
+ return head;
+ low = fold_convert (type, low);
+ high = low;
+ }
+ else
+ {
+ /* If the entire case range is unreachable, ignore it. */
+ if ((TREE_CODE (min_value) == INTEGER_CST
+ && tree_int_cst_compare (high, min_value) < 0)
+ || (TREE_CODE (max_value) == INTEGER_CST
+ && tree_int_cst_compare (low, max_value) > 0))
+ return head;
+
+ /* If the lower bound is less than the index type's minimum
+ value, truncate the range bounds. */
+ if (TREE_CODE (min_value) == INTEGER_CST
+ && tree_int_cst_compare (low, min_value) < 0)
+ low = min_value;
+ low = fold_convert (type, low);
+
+ /* If the upper bound is greater than the index type's maximum
+ value, truncate the range bounds. */
+ if (TREE_CODE (max_value) == INTEGER_CST
+ && tree_int_cst_compare (high, max_value) > 0)
+ high = max_value;
+ high = fold_convert (type, high);
+ }
+
/* Add this label to the chain. */
r = ggc_alloc (sizeof (struct case_node));
if (i == count)
{
- if (count >= MAX_CASE_BIT_TESTS)
- abort ();
- test[i].hi = 0;
- test[i].lo = 0;
+ gcc_assert (count < MAX_CASE_BIT_TESTS);
+ test[i].hi = 0;
+ test[i].lo = 0;
test[i].label = label;
test[i].bits = 1;
count++;
else
test[i].bits++;
- lo = tree_low_cst (fold (build2 (MINUS_EXPR, index_type,
- n->low, minval)), 1);
- hi = tree_low_cst (fold (build2 (MINUS_EXPR, index_type,
- n->high, minval)), 1);
+ lo = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
+ n->low, minval), 1);
+ hi = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
+ n->high, minval), 1);
for (j = lo; j <= hi; j++)
if (j >= HOST_BITS_PER_WIDE_INT)
test[i].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT);
qsort (test, count, sizeof(*test), case_bit_test_cmp);
- index_expr = fold (build2 (MINUS_EXPR, index_type,
- convert (index_type, index_expr),
- convert (index_type, minval)));
+ index_expr = fold_build2 (MINUS_EXPR, index_type,
+ fold_convert (index_type, index_expr),
+ fold_convert (index_type, minval));
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
do_pending_stack_adjust ();
{
tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
rtx default_label = 0;
- struct case_node *n, *m;
+ struct case_node *n;
unsigned int count, uniq;
rtx index;
rtx table_label;
int ncases;
rtx *labelvec;
- int i;
+ int i, fail;
rtx before_case, end, lab;
tree vec = SWITCH_LABELS (exp);
struct case_node *case_list = 0;
/* Label to jump to if no case matches. */
- tree default_label_decl = 0;
+ tree default_label_decl;
/* The switch body is lowered in gimplify.c, we should never have
switches with a non-NULL SWITCH_BODY here. */
- if (SWITCH_BODY (exp) || !SWITCH_LABELS (exp))
- abort ();
+ gcc_assert (!SWITCH_BODY (exp));
+ gcc_assert (SWITCH_LABELS (exp));
+
+ do_pending_stack_adjust ();
- for (i = TREE_VEC_LENGTH (vec); --i >= 0; )
+ /* An ERROR_MARK occurs for various reasons including invalid data type. */
+ if (index_type != error_mark_node)
{
- tree elt = TREE_VEC_ELT (vec, i);
+ tree elt;
+ bitmap label_bitmap;
- /* Handle default labels specially. */
- if (!CASE_HIGH (elt) && !CASE_LOW (elt))
- {
-#ifdef ENABLE_CHECKING
- if (default_label_decl != 0)
- abort ();
-#endif
- default_label_decl = CASE_LABEL (elt);
- }
- else
- case_list = add_case_node (case_list, CASE_LOW (elt), CASE_HIGH (elt),
- CASE_LABEL (elt));
- }
+ /* cleanup_tree_cfg removes all SWITCH_EXPR with their index
+ expressions being INTEGER_CST. */
+ gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
- do_pending_stack_adjust ();
+ /* The default case is at the end of TREE_VEC. */
+ elt = TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec) - 1);
+ gcc_assert (!CASE_HIGH (elt));
+ gcc_assert (!CASE_LOW (elt));
+ default_label_decl = CASE_LABEL (elt);
- /* Make sure start points to something that won't need any transformation
- before the end of this function. */
- if (!NOTE_P (get_last_insn ()))
- emit_note (NOTE_INSN_DELETED);
+ for (i = TREE_VEC_LENGTH (vec) - 1; --i >= 0; )
+ {
+ elt = TREE_VEC_ELT (vec, i);
+ gcc_assert (CASE_LOW (elt));
+ case_list = add_case_node (case_list, index_type,
+ CASE_LOW (elt), CASE_HIGH (elt),
+ CASE_LABEL (elt));
+ }
- start = get_last_insn ();
- /* An ERROR_MARK occurs for various reasons including invalid data type. */
- if (index_type != error_mark_node)
- {
- /* If we don't have a default-label, create one here,
- after the body of the switch. */
- if (default_label_decl == 0)
+ /* Make sure start points to something that won't need any
+ transformation before the end of this function. */
+ start = get_last_insn ();
+ if (! NOTE_P (start))
{
- default_label_decl
- = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- expand_label (default_label_decl);
+ emit_note (NOTE_INSN_DELETED);
+ start = get_last_insn ();
}
+
default_label = label_rtx (default_label_decl);
before_case = get_last_insn ();
- /* Get upper and lower bounds of case values.
- Also convert all the case values to the index expr's data type. */
+ /* Get upper and lower bounds of case values. */
uniq = 0;
count = 0;
+ label_bitmap = BITMAP_ALLOC (NULL);
for (n = case_list; n; n = n->right)
{
- /* Check low and high label values are integers. */
- if (TREE_CODE (n->low) != INTEGER_CST)
- abort ();
- if (TREE_CODE (n->high) != INTEGER_CST)
- abort ();
-
- n->low = convert (index_type, n->low);
- n->high = convert (index_type, n->high);
-
/* Count the elements and track the largest and smallest
of them (treating them as signed even if they are not). */
if (count++ == 0)
if (! tree_int_cst_equal (n->low, n->high))
count++;
- /* Count the number of unique case node targets. */
- uniq++;
+ /* If we have not seen this label yet, then increase the
+ number of unique case node targets seen. */
lab = label_rtx (n->code_label);
- for (m = case_list; m != n; m = m->right)
- if (label_rtx (m->code_label) == lab)
- {
- uniq--;
- break;
- }
+ if (!bitmap_bit_p (label_bitmap, CODE_LABEL_NUMBER (lab)))
+ {
+ bitmap_set_bit (label_bitmap, CODE_LABEL_NUMBER (lab));
+ uniq++;
+ }
}
- /* Compute span of values. */
- if (count != 0)
- range = fold (build2 (MINUS_EXPR, index_type, maxval, minval));
+ BITMAP_FREE (label_bitmap);
+ /* cleanup_tree_cfg removes all SWITCH_EXPR with a single
+ destination, such as one with a default case only. However,
+ it doesn't remove cases that are out of range for the switch
+ type, so we may still get a zero here. */
if (count == 0)
{
- expand_expr (index_expr, const0_rtx, VOIDmode, 0);
emit_jump (default_label);
+ return;
}
+ /* Compute span of values. */
+ range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
+
/* Try implementing this switch statement by a short sequence of
bit-wise comparisons. However, we let the binary-tree case
below handle constant index expressions. */
- else if (CASE_USE_BIT_TESTS
- && ! TREE_CONSTANT (index_expr)
- && compare_tree_int (range, GET_MODE_BITSIZE (word_mode)) < 0
- && compare_tree_int (range, 0) > 0
- && lshift_cheap_p ()
- && ((uniq == 1 && count >= 3)
- || (uniq == 2 && count >= 5)
- || (uniq == 3 && count >= 6)))
+ if (CASE_USE_BIT_TESTS
+ && ! TREE_CONSTANT (index_expr)
+ && compare_tree_int (range, GET_MODE_BITSIZE (word_mode)) < 0
+ && compare_tree_int (range, 0) > 0
+ && lshift_cheap_p ()
+ && ((uniq == 1 && count >= 3)
+ || (uniq == 2 && count >= 5)
+ || (uniq == 3 && count >= 6)))
{
/* Optimize the case where all the case values fit in a
word without having to subtract MINVAL. In this case,
if (compare_tree_int (minval, 0) > 0
&& compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
{
- minval = integer_zero_node;
+ minval = build_int_cst (index_type, 0);
range = maxval;
}
emit_case_bit_tests (index_type, index_expr, minval, range,
#ifndef ASM_OUTPUT_ADDR_DIFF_ELT
|| flag_pic
#endif
+ || !flag_jump_tables
|| TREE_CONSTANT (index_expr)
/* If neither casesi or tablejump is available, we can
only go this way. */
if (MEM_P (index))
index = copy_to_reg (index);
- if (GET_CODE (index) == CONST_INT
- || TREE_CODE (index_expr) == INTEGER_CST)
- {
- /* Make a tree node with the proper constant value
- if we don't already have one. */
- if (TREE_CODE (index_expr) != INTEGER_CST)
- {
- index_expr
- = build_int_cst (NULL_TREE, INTVAL (index),
- unsignedp || INTVAL (index) >= 0 ? 0 : -1);
- index_expr = convert (index_type, index_expr);
- }
- /* For constant index expressions we need only
- issue an unconditional branch to the appropriate
- target code. The job of removing any unreachable
- code is left to the optimization phase if the
- "-O" option is specified. */
- for (n = case_list; n; n = n->right)
- if (! tree_int_cst_lt (index_expr, n->low)
- && ! tree_int_cst_lt (n->high, index_expr))
- break;
-
- if (n)
- emit_jump (label_rtx (n->code_label));
- else
- emit_jump (default_label);
- }
- else
- {
- /* If the index expression is not constant we generate
- a binary decision tree to select the appropriate
- target code. This is done as follows:
+ /* We generate a binary decision tree to select the
+ appropriate target code. This is done as follows:
- The list of cases is rearranged into a binary tree,
- nearly optimal assuming equal probability for each case.
+ The list of cases is rearranged into a binary tree,
+ nearly optimal assuming equal probability for each case.
- The tree is transformed into RTL, eliminating
- redundant test conditions at the same time.
+ The tree is transformed into RTL, eliminating
+ redundant test conditions at the same time.
- If program flow could reach the end of the
- decision tree an unconditional jump to the
- default code is emitted. */
+ If program flow could reach the end of the
+ decision tree an unconditional jump to the
+ default code is emitted. */
- use_cost_table
- = (TREE_CODE (orig_type) != ENUMERAL_TYPE
- && estimate_case_costs (case_list));
- balance_case_nodes (&case_list, NULL);
- emit_case_nodes (index, case_list, default_label, index_type);
- emit_jump (default_label);
- }
+ use_cost_table
+ = (TREE_CODE (orig_type) != ENUMERAL_TYPE
+ && estimate_case_costs (case_list));
+ balance_case_nodes (&case_list, NULL);
+ emit_case_nodes (index, case_list, default_label, index_type);
+ emit_jump (default_label);
}
else
{
if (! try_casesi (index_type, index_expr, minval, range,
table_label, default_label))
{
- index_type = integer_type_node;
+ bool ok;
/* Index jumptables from zero for suitable values of
minval to avoid a subtraction. */
&& compare_tree_int (minval, 0) > 0
&& compare_tree_int (minval, 3) < 0)
{
- minval = integer_zero_node;
+ minval = build_int_cst (index_type, 0);
range = maxval;
}
- if (! try_tablejump (index_type, index_expr, minval, range,
- table_label, default_label))
- abort ();
+ ok = try_tablejump (index_type, index_expr, minval, range,
+ table_label, default_label);
+ gcc_assert (ok);
}
/* Get table of labels to jump to, in order of case index. */
value since that should fit in a HOST_WIDE_INT while the
actual values may not. */
HOST_WIDE_INT i_low
- = tree_low_cst (fold (build2 (MINUS_EXPR, index_type,
- n->low, minval)), 1);
+ = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
+ n->low, minval), 1);
HOST_WIDE_INT i_high
- = tree_low_cst (fold (build2 (MINUS_EXPR, index_type,
- n->high, minval)), 1);
+ = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
+ n->high, minval), 1);
HOST_WIDE_INT i;
for (i = i_low; i <= i_high; i ++)
emit_jump_insn (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
gen_rtvec_v (ncases, labelvec)));
- /* If the case insn drops through the table,
- after the table we must jump to the default-label.
- Otherwise record no drop-through after the table. */
-#ifdef CASE_DROPS_THROUGH
- emit_jump (default_label);
-#else
+ /* Record no drop-through after the table. */
emit_barrier ();
-#endif
}
before_case = NEXT_INSN (before_case);
end = get_last_insn ();
- if (squeeze_notes (&before_case, &end))
- abort ();
+ fail = squeeze_notes (&before_case, &end);
+ gcc_assert (!fail);
reorder_insns (before_case, end, start);
}
estimate_case_costs (case_node_ptr node)
{
tree min_ascii = integer_minus_one_node;
- tree max_ascii = convert (TREE_TYPE (node->high),
- build_int_cst (NULL_TREE, 127, 0));
+ tree max_ascii = build_int_cst (TREE_TYPE (node->high), 127);
case_node_ptr n;
int i;
if (node->left)
return 0;
- low_minus_one = fold (build2 (MINUS_EXPR, TREE_TYPE (node->low),
- node->low, integer_one_node));
+ low_minus_one = fold_build2 (MINUS_EXPR, TREE_TYPE (node->low),
+ node->low,
+ build_int_cst (TREE_TYPE (node->low), 1));
/* If the subtraction above overflowed, we can't verify anything.
Otherwise, look for a parent that tests our value - 1. */
if (node->right)
return 0;
- high_plus_one = fold (build2 (PLUS_EXPR, TREE_TYPE (node->high),
- node->high, integer_one_node));
+ high_plus_one = fold_build2 (PLUS_EXPR, TREE_TYPE (node->high),
+ node->high,
+ build_int_cst (TREE_TYPE (node->high), 1));
/* If the addition above overflowed, we can't verify anything.
Otherwise, look for a parent that tests our value + 1. */
else if (node->right != 0 && node->left == 0)
{
- /* Here we have a right child but no left so we issue conditional
+ /* Here we have a right child but no left so we issue a conditional
branch to default and process the right child.
- Omit the conditional branch to default if we it avoid only one
- right child; it costs too much space to save so little time. */
+ Omit the conditional branch to default if the right child
+ does not have any children and is single valued; it would
+ cost too much space to save so little time. */
if (node->right->right || node->right->left
|| !tree_int_cst_equal (node->right->low, node->right->high))
new_index = expand_simple_binop (mode, MINUS, index, low_rtx,
NULL_RTX, unsignedp,
OPTAB_WIDEN);
- new_bound = expand_expr (fold (build2 (MINUS_EXPR, type,
- high, low)),
+ new_bound = expand_expr (fold_build2 (MINUS_EXPR, type,
+ high, low),
NULL_RTX, mode, 0);
emit_cmp_and_jump_insns (new_index, new_bound, GT, NULL_RTX,