/* 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, 2005, 2006, 2007
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
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;
}
*p, operand_num);
/* Make a copy of the constraint. */
- buf = alloca (c_len + 1);
+ buf = XALLOCAVEC (char, c_len + 1);
strcpy (buf, constraint);
/* Swap the first character and the `=' or `+'. */
buf[p - constraint] = buf[0];
}
break;
- case 'V': case 'm': case 'o':
+ case 'V': case TARGET_MEM_CONSTRAINT: case 'o':
*allows_mem = true;
break;
}
break;
- case 'V': case 'm': case 'o':
+ case 'V': case TARGET_MEM_CONSTRAINT: case 'o':
*allows_mem = true;
break;
void *data)
{
tree decl = *declp;
- const HARD_REG_SET *regs = data;
+ const HARD_REG_SET *const regs = (const HARD_REG_SET *) data;
if (TREE_CODE (decl) == VAR_DECL)
{
STRING is the instruction template.
OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
Each output or input has an expression in the TREE_VALUE and
- and a tree list in TREE_PURPOSE which in turn contains a constraint
+ a tree list in TREE_PURPOSE which in turn contains a constraint
name in TREE_VALUE (or NULL_TREE) and a constraint string
in TREE_PURPOSE.
CLOBBERS is a list of STRING_CST nodes each naming a hard register
tree t;
int i;
/* Vector of RTX's of evaluated output operands. */
- rtx *output_rtx = alloca (noutputs * sizeof (rtx));
- int *inout_opnum = alloca (noutputs * sizeof (int));
- rtx *real_output_rtx = alloca (noutputs * sizeof (rtx));
- enum machine_mode *inout_mode
- = alloca (noutputs * sizeof (enum machine_mode));
- const char **constraints
- = alloca ((noutputs + ninputs) * sizeof (const char *));
+ rtx *output_rtx = XALLOCAVEC (rtx, noutputs);
+ int *inout_opnum = XALLOCAVEC (int, noutputs);
+ rtx *real_output_rtx = XALLOCAVEC (rtx, noutputs);
+ enum machine_mode *inout_mode = XALLOCAVEC (enum machine_mode, noutputs);
+ const char **constraints = XALLOCAVEC (const char *, noutputs + ninputs);
int old_generating_concat_p = generating_concat_p;
/* An ASM with no outputs needs to be treated as volatile, for now. */
if (real_output_rtx[i])
emit_move_insn (real_output_rtx[i], output_rtx[i]);
+ crtl->has_asm_statement = 1;
free_temp_slots ();
}
tree type;
value = expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
- if (GIMPLE_TUPLE_P (exp))
- type = void_type_node;
- else
type = TREE_TYPE (exp);
/* If all we do is reference a volatile value in memory,
(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))
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
case MODIFY_EXPR:
- case GIMPLE_MODIFY_STMT:
case INIT_EXPR:
case TARGET_EXPR:
case CALL_EXPR:
return 0;
warn:
- warning (0, "%Hvalue computed is not used", &locus);
+ warning (OPT_Wunused_value, "%Hvalue computed is not used", &locus);
return 1;
}
}
expand_null_return ();
return;
}
- else if ((TREE_CODE (retval) == GIMPLE_MODIFY_STMT
+ else if ((TREE_CODE (retval) == MODIFY_EXPR
|| TREE_CODE (retval) == INIT_EXPR)
- && TREE_CODE (GENERIC_TREE_OPERAND (retval, 0)) == RESULT_DECL)
- retval_rhs = GENERIC_TREE_OPERAND (retval, 1);
+ && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
+ retval_rhs = TREE_OPERAND (retval, 1);
else
retval_rhs = retval;
(and in expand_call). */
else if (retval_rhs != 0
- && TYPE_MODE (GENERIC_TREE_TYPE (retval_rhs)) == BLKmode
+ && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
&& REG_P (result_rtl))
{
int i;
int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
unsigned int bitsize
= MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)), BITS_PER_WORD);
- rtx *result_pseudos = alloca (sizeof (rtx) * n_regs);
+ rtx *result_pseudos = XALLOCAVEC (rtx, n_regs);
rtx result_reg, src = NULL_RTX, dst = NULL_RTX;
rtx result_val = expand_normal (retval_rhs);
enum machine_mode tmpmode, result_reg_mode;
*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;
{
/* Clobber the FP when we get here, so we have to make sure it's
marked as used by this function. */
- emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+ emit_use (hard_frame_pointer_rtx);
/* Mark the static chain as clobbered here so life information
doesn't get messed up for it. */
- emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
+ emit_clobber (static_chain_rtx);
#ifdef HAVE_nonlocal_goto
if (! HAVE_nonlocal_goto)
{
/* 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)));
+ emit_move_insn (crtl->args.internal_arg_pointer,
+ copy_to_reg (get_arg_pointer_save_area ()));
}
}
#endif
/* 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
static int
case_bit_test_cmp (const void *p1, const void *p2)
{
- const struct case_bit_test *d1 = p1;
- const struct case_bit_test *d2 = p2;
+ const struct case_bit_test *const d1 = (const struct case_bit_test *) p1;
+ const struct case_bit_test *const d2 = (const struct case_bit_test *) p2;
if (d2->bits != d1->bits)
return d2->bits - d1->bits;
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
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;
/* Get table of labels to jump to, in order of case index. */
ncases = tree_low_cst (range, 0) + 1;
- labelvec = alloca (ncases * sizeof (rtx));
+ labelvec = XALLOCAVEC (rtx, ncases);
memset (labelvec, 0, ncases * sizeof (rtx));
for (n = case_list; n; n = n->right)
= 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);
}
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);