GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file handles the generation of rtl code from tree structure
above the level of expressions, using subroutines in exp*.c and emit-rtl.c.
#include "optabs.h"
#include "target.h"
#include "regs.h"
+#include "alloc-pool.h"
\f
/* Functions and data structures for expanding case statements. */
For very small, suitable switch statements, we can generate a series
of simple bit test and branches instead. */
-struct case_node GTY(())
+struct case_node
{
struct case_node *left; /* Left son in binary tree */
struct case_node *right; /* Right son in binary tree; also node chain */
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, tree);
+ tree, tree, tree, alloc_pool);
\f
/* Return the rtx-label that corresponds to a LABEL_DECL,
else
p = cfun;
- p->expr->x_forced_labels = gen_rtx_EXPR_LIST (VOIDmode, ref,
- p->expr->x_forced_labels);
+ forced_labels = gen_rtx_EXPR_LIST (VOIDmode, ref, forced_labels);
return ref;
}
&& REGNO (DECL_RTL (decl)) < FIRST_PSEUDO_REGISTER)
{
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 (*regs, regno))
- return decl;
+
+ if (overlaps_hard_reg_set_p (*regs, GET_MODE (reg), REGNO (reg)))
+ return decl;
}
walk_subtrees = 0;
}
if (real_output_rtx[i])
emit_move_insn (real_output_rtx[i], output_rtx[i]);
+ crtl->has_asm_statement = 1;
free_temp_slots ();
}
{
if (o[i] != TREE_VALUE (tail))
{
- expand_assignment (o[i], TREE_VALUE (tail));
+ expand_assignment (o[i], TREE_VALUE (tail), false);
free_temp_slots ();
/* Restore the original value so that it's correct the next
(potential) location of the expression. */
int
-warn_if_unused_value (tree exp, location_t locus)
+warn_if_unused_value (const_tree exp, location_t locus)
{
restart:
if (TREE_USED (exp) || TREE_NO_WARNING (exp))
return 0;
warn:
- warning (0, "%Hvalue computed is not used", &locus);
+ warning (OPT_Wunused_value, "%Hvalue computed is not used", &locus);
return 1;
}
}
*that* node in turn will point to the relevant FUNCTION_DECL node. */
int
-is_body_block (tree stmt)
+is_body_block (const_tree stmt)
{
if (lang_hooks.no_body_blocks)
return 0;
/* Now restore our arg pointer from the address at which it
was saved in our stack frame. */
emit_move_insn (virtual_incoming_args_rtx,
- copy_to_reg (get_arg_pointer_save_area (cfun)));
+ copy_to_reg (get_arg_pointer_save_area ()));
}
}
#endif
emit_insn (gen_nonlocal_goto_receiver ());
#endif
- /* @@@ This is a kludge. Not all machine descriptions define a blockage
- insn, but we must not allow the code we just generated to be reordered
- by scheduling. Specifically, the update of the frame pointer must
- happen immediately, not later. So emit an ASM_INPUT to act as blockage
- insn. */
- emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+ /* We must not allow the code we just generated to be reordered by
+ scheduling. Specifically, the update of the frame pointer must
+ happen immediately, not later. */
+ emit_insn (gen_blockage ());
}
\f
/* Generate RTL for the automatic variable declaration DECL.
/* Note if the object is a user variable. */
if (!DECL_ARTIFICIAL (decl))
- {
mark_user_reg (DECL_RTL (decl));
- /* Trust user variables which have a pointer type to really
- be pointers. Do not trust compiler generated temporaries
- as our type system is totally busted as it relates to
- pointer arithmetic which translates into lots of compiler
- generated objects with pointer types, but which are not really
- pointers. */
- if (POINTER_TYPE_P (type))
- mark_reg_pointer (DECL_RTL (decl),
- TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
- }
+ if (POINTER_TYPE_P (type))
+ mark_reg_pointer (DECL_RTL (decl),
+ TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
}
else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
void
expand_stack_restore (tree var)
{
- rtx sa = DECL_RTL (var);
+ rtx sa = expand_normal (var);
+ sa = convert_memory_address (Pmode, sa);
emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX);
}
\f
static struct case_node *
add_case_node (struct case_node *head, tree type, tree low, tree high,
- tree label)
+ tree label, alloc_pool case_node_pool)
{
tree min_value, max_value;
struct case_node *r;
/* Add this label to the chain. Make sure to drop overflow flags. */
- r = ggc_alloc (sizeof (struct case_node));
+ r = (struct case_node *) pool_alloc (case_node_pool);
r->low = build_int_cst_wide (TREE_TYPE (low), TREE_INT_CST_LOW (low),
TREE_INT_CST_HIGH (low));
r->high = build_int_cst_wide (TREE_TYPE (high), TREE_INT_CST_LOW (high),
/* By default, enable case bit tests on targets with ashlsi3. */
#ifndef CASE_USE_BIT_TESTS
-#define CASE_USE_BIT_TESTS (ashl_optab->handlers[word_mode].insn_code \
+#define CASE_USE_BIT_TESTS (optab_handler (ashl_optab, word_mode)->insn_code \
!= CODE_FOR_nothing)
#endif
mode = TYPE_MODE (index_type);
expr = expand_normal (range);
- emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1,
- default_label);
+ if (default_label)
+ emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1,
+ default_label);
index = convert_to_mode (word_mode, index, 0);
index = expand_binop (word_mode, ashl_optab, const1_rtx,
word_mode, 1, test[i].label);
}
- emit_jump (default_label);
+ if (default_label)
+ emit_jump (default_label);
}
#ifndef HAVE_casesi
rtx table_label;
int ncases;
rtx *labelvec;
- int i, fail;
+ int i;
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;
+ tree default_label_decl = NULL_TREE;
+
+ alloc_pool case_node_pool = create_alloc_pool ("struct case_node pool",
+ sizeof (struct case_node),
+ 100);
/* The switch body is lowered in gimplify.c, we should never have
switches with a non-NULL SWITCH_BODY here. */
{
tree elt;
bitmap label_bitmap;
+ int vl = TREE_VEC_LENGTH (vec);
/* cleanup_tree_cfg removes all SWITCH_EXPR with their index
expressions being INTEGER_CST. */
gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
- /* 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);
+ /* The default case, if ever taken, is at the end of TREE_VEC. */
+ elt = TREE_VEC_ELT (vec, vl - 1);
+ if (!CASE_LOW (elt) && !CASE_HIGH (elt))
+ {
+ default_label_decl = CASE_LABEL (elt);
+ --vl;
+ }
- for (i = TREE_VEC_LENGTH (vec) - 1; --i >= 0; )
+ for (i = vl - 1; i >= 0; --i)
{
tree low, high;
elt = TREE_VEC_ELT (vec, i);
high = CASE_HIGH (elt);
/* Discard empty ranges. */
- if (high && INT_CST_LT (high, low))
+ if (high && tree_int_cst_lt (high, low))
continue;
case_list = add_case_node (case_list, index_type, low, high,
- CASE_LABEL (elt));
+ CASE_LABEL (elt), case_node_pool);
}
before_case = start = get_last_insn ();
- default_label = label_rtx (default_label_decl);
+ if (default_label_decl)
+ default_label = label_rtx (default_label_decl);
/* Get upper and lower bounds of case values. */
}
else
{
- if (INT_CST_LT (n->low, minval))
+ if (tree_int_cst_lt (n->low, minval))
minval = n->low;
- if (INT_CST_LT (maxval, n->high))
+ if (tree_int_cst_lt (maxval, n->high))
maxval = n->high;
}
/* A range counts double, since it requires two compares. */
type, so we may still get a zero here. */
if (count == 0)
{
- emit_jump (default_label);
+ if (default_label)
+ emit_jump (default_label);
+ free_alloc_pool (case_node_pool);
return;
}
&& 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);
+ if (default_label)
+ emit_jump (default_label);
}
else
{
+ rtx fallback_label = label_rtx (case_list->code_label);
table_label = gen_label_rtx ();
if (! try_casesi (index_type, index_expr, minval, range,
- table_label, default_label))
+ table_label, default_label, fallback_label))
{
bool ok;
= gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
}
- /* Fill in the gaps with the default. */
+ /* Fill in the gaps with the default. We may have gaps at
+ the beginning if we tried to avoid the minval subtraction,
+ so substitute some label even if the default label was
+ deemed unreachable. */
+ if (!default_label)
+ default_label = fallback_label;
for (i = 0; i < ncases; i++)
if (labelvec[i] == 0)
labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label);
before_case = NEXT_INSN (before_case);
end = get_last_insn ();
- fail = squeeze_notes (&before_case, &end);
- gcc_assert (!fail);
reorder_insns (before_case, end, start);
}
free_temp_slots ();
+ free_alloc_pool (case_node_pool);
}
/* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. */
for (n = node; n; n = n->right)
{
- if ((INT_CST_LT (n->low, min_ascii)) || INT_CST_LT (max_ascii, n->high))
+ if (tree_int_cst_lt (n->low, min_ascii)
+ || tree_int_cst_lt (max_ascii, n->high))
return 0;
for (i = (HOST_WIDE_INT) TREE_INT_CST_LOW (n->low);
emit_case_nodes (index, node->left, default_label, index_type);
/* If left-hand subtree does nothing,
go to default. */
- emit_jump (default_label);
+ if (default_label)
+ emit_jump (default_label);
/* Code branches here for the right-hand subtree. */
expand_label (test_label);
{
/* If the left-hand subtree fell through,
don't let it fall into the right-hand subtree. */
- emit_jump (default_label);
+ if (default_label)
+ emit_jump (default_label);
expand_label (test_label);
emit_case_nodes (index, node->right, default_label, index_type);