aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/stmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/stmt.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/stmt.c3369
1 files changed, 0 insertions, 3369 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/stmt.c b/gcc-4.2.1-5666.3/gcc/stmt.c
deleted file mode 100644
index b92b987eb..000000000
--- a/gcc-4.2.1-5666.3/gcc/stmt.c
+++ /dev/null
@@ -1,3369 +0,0 @@
-/* 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
- 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
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-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. */
-
-/* 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.
- The functions whose names start with `expand_' are called by the
- expander to generate RTL instructions for various kinds of constructs. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-
-#include "rtl.h"
-#include "hard-reg-set.h"
-#include "tree.h"
-#include "tm_p.h"
-#include "flags.h"
-#include "except.h"
-#include "function.h"
-#include "insn-config.h"
-#include "expr.h"
-#include "libfuncs.h"
-#include "recog.h"
-#include "machmode.h"
-#include "toplev.h"
-#include "output.h"
-#include "ggc.h"
-#include "langhooks.h"
-#include "predict.h"
-#include "optabs.h"
-#include "target.h"
-#include "regs.h"
-
-/* Functions and data structures for expanding case statements. */
-
-/* Case label structure, used to hold info on labels within case
- statements. We handle "range" labels; for a single-value label
- as in C, the high and low limits are the same.
-
- We start with a vector of case nodes sorted in ascending order, and
- the default label as the last element in the vector. Before expanding
- to RTL, we transform this vector into a list linked via the RIGHT
- fields in the case_node struct. Nodes with higher case values are
- later in the list.
-
- Switch statements can be output in three forms. A branch table is
- used if there are more than a few labels and the labels are dense
- within the range between the smallest and largest case value. If a
- branch table is used, no further manipulations are done with the case
- node chain.
-
- The alternative to the use of a branch table is to generate a series
- of compare and jump insns. When that is done, we use the LEFT, RIGHT,
- and PARENT fields to hold a binary tree. Initially the tree is
- totally unbalanced, with everything on the right. We balance the tree
- with nodes on the left having lower case values than the parent
- and nodes on the right having higher values. We then output the tree
- in order.
-
- 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 *left; /* Left son in binary tree */
- struct case_node *right; /* Right son in binary tree; also node chain */
- struct case_node *parent; /* Parent of node in binary tree */
- tree low; /* Lowest index value for this label */
- tree high; /* Highest index value for this label */
- tree code_label; /* Label to jump to when node matches */
-};
-
-typedef struct case_node case_node;
-typedef struct case_node *case_node_ptr;
-
-/* These are used by estimate_case_costs and balance_case_nodes. */
-
-/* This must be a signed type, and non-ANSI compilers lack signed char. */
-static short cost_table_[129];
-static int use_cost_table;
-static int cost_table_initialized;
-
-/* Special care is needed because we allow -1, but TREE_INT_CST_LOW
- is unsigned. */
-#define COST_TABLE(I) cost_table_[(unsigned HOST_WIDE_INT) ((I) + 1)]
-
-static int n_occurrences (int, const char *);
-static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *);
-static void expand_nl_goto_receiver (void);
-static bool check_operand_nalternatives (tree, tree);
-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 void expand_value_return (rtx);
-static int estimate_case_costs (case_node_ptr);
-static bool lshift_cheap_p (void);
-static int case_bit_test_cmp (const void *, const void *);
-static void emit_case_bit_tests (tree, tree, tree, tree, case_node_ptr, rtx);
-static void balance_case_nodes (case_node_ptr *, case_node_ptr);
-static int node_has_low_bound (case_node_ptr, tree);
-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, tree);
-
-
-/* Return the rtx-label that corresponds to a LABEL_DECL,
- creating it if necessary. */
-
-rtx
-label_rtx (tree label)
-{
- gcc_assert (TREE_CODE (label) == LABEL_DECL);
-
- if (!DECL_RTL_SET_P (label))
- {
- rtx r = gen_label_rtx ();
-/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
- unsigned align = DECL_ALIGN_UNIT (label);
- int align_log2 = exact_log2 (align);
-
-/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
- SET_DECL_RTL (label, r);
- if (FORCED_LABEL (label) || DECL_NONLOCAL (label))
- LABEL_PRESERVE_P (r) = 1;
-/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
-
- if (align_log2 >= 0 && align_log2 <= 0xFF)
- SET_LABEL_ALIGN (r, align_log2, align - 1);
-/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
- }
-
- return DECL_RTL (label);
-}
-
-/* As above, but also put it on the forced-reference list of the
- function that contains it. */
-rtx
-force_label_rtx (tree label)
-{
- rtx ref = label_rtx (label);
- tree function = decl_function_context (label);
- struct function *p;
-
- gcc_assert (function);
-
- if (function != current_function_decl)
- p = find_function_data (function);
- else
- p = cfun;
-
- p->expr->x_forced_labels = gen_rtx_EXPR_LIST (VOIDmode, ref,
- p->expr->x_forced_labels);
- return ref;
-}
-
-/* Add an unconditional jump to LABEL as the next sequential instruction. */
-
-void
-emit_jump (rtx label)
-{
- do_pending_stack_adjust ();
- emit_jump_insn (gen_jump (label));
- emit_barrier ();
-}
-
-/* Emit code to jump to the address
- specified by the pointer expression EXP. */
-
-void
-expand_computed_goto (tree exp)
-{
- rtx x = expand_normal (exp);
-
- x = convert_memory_address (Pmode, x);
-
- do_pending_stack_adjust ();
- emit_indirect_jump (x);
-}
-
-/* Handle goto statements and the labels that they can go to. */
-
-/* Specify the location in the RTL code of a label LABEL,
- which is a LABEL_DECL tree node.
-
- APPLE LOCAL begin for-fsf-4_4 3274130 5295549
- This is used for those labels created by the front-end that survive
- through CFG generation, including all user labels. (Some labels
- are removed by cleanup_dead_labels in tree-cfg.c.)
-
- APPLE LOCAL end for-fsf-4_4 3274130 5295549
- Note that this has nothing to do with defining label *names*.
- Languages vary in how they do that and what that even means. */
-
-void
-expand_label (tree label)
-{
- rtx label_r = label_rtx (label);
-
- do_pending_stack_adjust ();
- emit_label (label_r);
- if (DECL_NAME (label))
- LABEL_NAME (DECL_RTL (label)) = IDENTIFIER_POINTER (DECL_NAME (label));
-
- if (DECL_NONLOCAL (label))
- {
- expand_nl_goto_receiver ();
- nonlocal_goto_handler_labels
- = gen_rtx_EXPR_LIST (VOIDmode, label_r,
- nonlocal_goto_handler_labels);
- }
-
- if (FORCED_LABEL (label))
- forced_labels = gen_rtx_EXPR_LIST (VOIDmode, label_r, forced_labels);
-
- if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
- maybe_set_first_label_num (label_r);
-}
-
-/* Generate RTL code for a `goto' statement with target label LABEL.
- LABEL should be a LABEL_DECL tree node that was or will later be
- defined with `expand_label'. */
-
-void
-expand_goto (tree label)
-{
-#ifdef ENABLE_CHECKING
- /* Check for a nonlocal goto to a containing function. Should have
- gotten translated to __builtin_nonlocal_goto. */
- tree context = decl_function_context (label);
- gcc_assert (!context || context == current_function_decl);
-#endif
-
- emit_jump (label_rtx (label));
-}
-
-/* Return the number of times character C occurs in string S. */
-static int
-n_occurrences (int c, const char *s)
-{
- int n = 0;
- while (*s)
- n += (*s++ == c);
- return n;
-}
-
-/* Generate RTL for an asm statement (explicit assembler code).
- STRING is a STRING_CST node containing the assembler code text,
- or an ADDR_EXPR containing a STRING_CST. VOL nonzero means the
- insn is volatile; don't optimize it. */
-
-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,
- ggc_strdup (TREE_STRING_POINTER (string)));
-
- MEM_VOLATILE_P (body) = vol;
-
- emit_insn (body);
-}
-
-/* Parse the output constraint pointed to by *CONSTRAINT_P. It is the
- OPERAND_NUMth output operand, indexed from zero. There are NINPUTS
- inputs and NOUTPUTS outputs to this extended-asm. Upon return,
- *ALLOWS_MEM will be TRUE iff the constraint allows the use of a
- memory operand. Similarly, *ALLOWS_REG will be TRUE iff the
- constraint allows the use of a register operand. And, *IS_INOUT
- will be true if the operand is read-write, i.e., if it is used as
- an input as well as an output. If *CONSTRAINT_P is not in
- canonical form, it will be made canonical. (Note that `+' will be
- replaced with `=' as part of this process.)
-
- Returns TRUE if all went well; FALSE if an error occurred. */
-
-bool
-parse_output_constraint (const char **constraint_p, int operand_num,
- int ninputs, int noutputs, bool *allows_mem,
- bool *allows_reg, bool *is_inout)
-{
- const char *constraint = *constraint_p;
- const char *p;
-
- /* Assume the constraint doesn't allow the use of either a register
- or memory. */
- *allows_mem = false;
- *allows_reg = false;
-
- /* Allow the `=' or `+' to not be at the beginning of the string,
- since it wasn't explicitly documented that way, and there is a
- large body of code that puts it last. Swap the character to
- the front, so as not to uglify any place else. */
- p = strchr (constraint, '=');
- if (!p)
- p = strchr (constraint, '+');
-
- /* If the string doesn't contain an `=', issue an error
- message. */
- if (!p)
- {
- error ("output operand constraint lacks %<=%>");
- return false;
- }
-
- /* If the constraint begins with `+', then the operand is both read
- from and written to. */
- *is_inout = (*p == '+');
-
- /* Canonicalize the output constraint so that it begins with `='. */
- if (p != constraint || *is_inout)
- {
- char *buf;
- size_t c_len = strlen (constraint);
-
- if (p != constraint)
- warning (0, "output constraint %qc for operand %d "
- "is not at the beginning",
- *p, operand_num);
-
- /* Make a copy of the constraint. */
- buf = alloca (c_len + 1);
- strcpy (buf, constraint);
- /* Swap the first character and the `=' or `+'. */
- buf[p - constraint] = buf[0];
- /* Make sure the first character is an `='. (Until we do this,
- it might be a `+'.) */
- buf[0] = '=';
- /* Replace the constraint with the canonicalized string. */
- *constraint_p = ggc_alloc_string (buf, c_len);
- constraint = *constraint_p;
- }
-
- /* Loop through the constraint string. */
- for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
- switch (*p)
- {
- case '+':
- case '=':
- error ("operand constraint contains incorrectly positioned "
- "%<+%> or %<=%>");
- return false;
-
- case '%':
- if (operand_num + 1 == ninputs + noutputs)
- {
- error ("%<%%%> constraint used with last operand");
- return false;
- }
- break;
-
- case 'V': case 'm': case 'o':
- *allows_mem = true;
- break;
-
- case '?': case '!': case '*': case '&': case '#':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',':
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case '[':
- error ("matching constraint not valid in output operand");
- return false;
-
- case '<': case '>':
- /* ??? Before flow, auto inc/dec insns are not supposed to exist,
- excepting those that expand_call created. So match memory
- and hope. */
- *allows_mem = true;
- break;
-
- case 'g': case 'X':
- *allows_reg = true;
- *allows_mem = true;
- break;
-
- case 'p': case 'r':
- *allows_reg = true;
- break;
-
- default:
- if (!ISALPHA (*p))
- break;
- if (REG_CLASS_FROM_CONSTRAINT (*p, p) != NO_REGS)
- *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT_STR
- else if (EXTRA_ADDRESS_CONSTRAINT (*p, p))
- *allows_reg = true;
- else if (EXTRA_MEMORY_CONSTRAINT (*p, p))
- *allows_mem = true;
- else
- {
- /* Otherwise we can't assume anything about the nature of
- the constraint except that it isn't purely registers.
- Treat it like "g" and hope for the best. */
- *allows_reg = true;
- *allows_mem = true;
- }
-#endif
- break;
- }
-
- return true;
-}
-
-/* Similar, but for input constraints. */
-
-bool
-parse_input_constraint (const char **constraint_p, int input_num,
- int ninputs, int noutputs, int ninout,
- const char * const * constraints,
- bool *allows_mem, bool *allows_reg)
-{
- const char *constraint = *constraint_p;
- const char *orig_constraint = constraint;
- size_t c_len = strlen (constraint);
- size_t j;
- bool saw_match = false;
-
- /* Assume the constraint doesn't allow the use of either
- a register or memory. */
- *allows_mem = false;
- *allows_reg = false;
-
- /* Make sure constraint has neither `=', `+', nor '&'. */
-
- for (j = 0; j < c_len; j += CONSTRAINT_LEN (constraint[j], constraint+j))
- switch (constraint[j])
- {
- case '+': case '=': case '&':
- if (constraint == orig_constraint)
- {
- error ("input operand constraint contains %qc", constraint[j]);
- return false;
- }
- break;
-
- case '%':
- if (constraint == orig_constraint
- && input_num + 1 == ninputs - ninout)
- {
- error ("%<%%%> constraint used with last operand");
- return false;
- }
- break;
-
- case 'V': case 'm': case 'o':
- *allows_mem = true;
- break;
-
- case '<': case '>':
- case '?': case '!': case '*': case '#':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',':
- break;
-
- /* Whether or not a numeric constraint allows a register is
- decided by the matching constraint, and so there is no need
- to do anything special with them. We must handle them in
- the default case, so that we don't unnecessarily force
- operands to memory. */
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- char *end;
- unsigned long match;
-
- saw_match = true;
-
- match = strtoul (constraint + j, &end, 10);
- if (match >= (unsigned long) noutputs)
- {
- error ("matching constraint references invalid operand number");
- return false;
- }
-
- /* Try and find the real constraint for this dup. Only do this
- if the matching constraint is the only alternative. */
- if (*end == '\0'
- && (j == 0 || (j == 1 && constraint[0] == '%')))
- {
- constraint = constraints[match];
- *constraint_p = constraint;
- c_len = strlen (constraint);
- j = 0;
- /* ??? At the end of the loop, we will skip the first part of
- the matched constraint. This assumes not only that the
- other constraint is an output constraint, but also that
- the '=' or '+' come first. */
- break;
- }
- else
- j = end - constraint;
- /* Anticipate increment at end of loop. */
- j--;
- }
- /* Fall through. */
-
- case 'p': case 'r':
- *allows_reg = true;
- break;
-
- case 'g': case 'X':
- *allows_reg = true;
- *allows_mem = true;
- break;
-
- default:
- if (! ISALPHA (constraint[j]))
- {
- error ("invalid punctuation %qc in constraint", constraint[j]);
- return false;
- }
- if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
- != NO_REGS)
- *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT_STR
- else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j], constraint + j))
- *allows_reg = true;
- else if (EXTRA_MEMORY_CONSTRAINT (constraint[j], constraint + j))
- *allows_mem = true;
- else
- {
- /* Otherwise we can't assume anything about the nature of
- the constraint except that it isn't purely registers.
- Treat it like "g" and hope for the best. */
- *allows_reg = true;
- *allows_mem = true;
- }
-#endif
- break;
- }
-
- if (saw_match && !*allows_reg)
- warning (0, "matching constraint does not allow a register");
-
- return true;
-}
-
-/* Return DECL iff there's an overlap between *REGS and DECL, where DECL
- can be an asm-declared register. Called via walk_tree. */
-
-static tree
-decl_overlaps_hard_reg_set_p (tree *declp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data)
-{
- tree decl = *declp;
- const HARD_REG_SET *regs = data;
-
- if (TREE_CODE (decl) == VAR_DECL)
- {
- if (DECL_HARD_REGISTER (decl)
- && REG_P (DECL_RTL (decl))
- && 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;
- }
- walk_subtrees = 0;
- }
- else if (TYPE_P (decl) || TREE_CODE (decl) == PARM_DECL)
- walk_subtrees = 0;
- return NULL_TREE;
-}
-
-/* If there is an overlap between *REGS and DECL, return the first overlap
- found. */
-tree
-tree_overlaps_hard_reg_set (tree decl, HARD_REG_SET *regs)
-{
- return walk_tree (&decl, decl_overlaps_hard_reg_set_p, regs, NULL);
-}
-
-/* Check for overlap between registers marked in CLOBBERED_REGS and
- anything inappropriate in T. Emit error and return the register
- variable definition for error, NULL_TREE for ok. */
-
-static bool
-tree_conflicts_with_clobbers_p (tree t, HARD_REG_SET *clobbered_regs)
-{
- /* Conflicts between asm-declared register variables and the clobber
- list are not allowed. */
- tree overlap = tree_overlaps_hard_reg_set (t, clobbered_regs);
-
- if (overlap)
- {
- error ("asm-specifier for variable %qs conflicts with asm clobber list",
- IDENTIFIER_POINTER (DECL_NAME (overlap)));
-
- /* Reset registerness to stop multiple errors emitted for a single
- variable. */
- DECL_REGISTER (overlap) = 0;
- return true;
- }
-
- return false;
-}
-
-/* Generate RTL for an asm statement with arguments.
- 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
- 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
- that is clobbered by this insn.
-
- Not all kinds of lvalue that may appear in OUTPUTS can be stored directly.
- Some elements of OUTPUTS may be replaced with trees representing temporary
- values. The caller should copy those temporary values to the originally
- specified lvalues.
-
- VOL nonzero means the insn is volatile; don't optimize it. */
-
-/* APPLE LOCAL begin CW asm blocks */
-static void
-expand_asm_operands (tree string, tree outputs, tree inputs,
- tree clobbers, int vol, tree uses, location_t locus)
-/* APPLE LOCAL end CW asm blocks */
-{
- rtvec argvec, constraintvec;
- rtx body;
- int ninputs = list_length (inputs);
- int noutputs = list_length (outputs);
- int ninout;
- /* APPLE LOCAL CW asm blocks */
- int nuses = 0;
- int nclobbers;
- HARD_REG_SET clobbered_regs;
- int clobber_conflict_found = 0;
- tree tail;
- 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 *));
- int old_generating_concat_p = generating_concat_p;
-
- /* An ASM with no outputs needs to be treated as volatile, for now. */
- if (noutputs == 0)
- vol = 1;
-
- if (! check_operand_nalternatives (outputs, inputs))
- return;
-
- string = resolve_asm_operand_names (string, outputs, inputs);
-
- /* Collect constraints. */
- i = 0;
- for (t = outputs; t ; t = TREE_CHAIN (t), i++)
- constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
- for (t = inputs; t ; t = TREE_CHAIN (t), i++)
- constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
-
- /* Sometimes we wish to automatically clobber registers across an asm.
- 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 (outputs, inputs, clobbers);
-
- /* Count the number of meaningful clobbered registers, ignoring what
- we would ignore later. */
- nclobbers = 0;
- CLEAR_HARD_REG_SET (clobbered_regs);
- for (tail = clobbers; tail; tail = TREE_CHAIN (tail))
- {
- const char *regname;
-
- if (TREE_VALUE (tail) == error_mark_node)
- return;
- regname = TREE_STRING_POINTER (TREE_VALUE (tail));
-
- i = decode_reg_name (regname);
- if (i >= 0 || i == -4)
- ++nclobbers;
- else if (i == -2)
- error ("unknown register name %qs in %<asm%>", regname);
-
- /* Mark clobbered registers. */
- if (i >= 0)
- {
- /* Clobbering the PIC register is an error. */
- /* APPLE LOCAL begin CW asm blocks */
- /* Clobbering of PIC register is allowed in CW asm block.
- We check this condition by checking value of 'uses'.
- 'uses' is non-null for a CW asm expression only. */
- if (uses == NULL && i == (int) PIC_OFFSET_TABLE_REGNUM)
- /* APPLE LOCAL end CW asm blocks */
- {
- error ("PIC register %qs clobbered in %<asm%>", regname);
- return;
- }
-
- SET_HARD_REG_BIT (clobbered_regs, i);
- }
- }
-
- /* First pass over inputs and outputs checks validity and sets
- mark_addressable if needed. */
-
- ninout = 0;
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- {
- tree val = TREE_VALUE (tail);
- tree type = TREE_TYPE (val);
- const char *constraint;
- bool is_inout;
- bool allows_reg;
- bool allows_mem;
-
- /* If there's an erroneous arg, emit no insn. */
- if (type == error_mark_node)
- return;
-
- /* Try to parse the output constraint. If that fails, there's
- no point in going further. */
- constraint = constraints[i];
- if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
- return;
-
- if (! allows_reg
- && (allows_mem
- || is_inout
- || (DECL_P (val)
- && REG_P (DECL_RTL (val))
- && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
- lang_hooks.mark_addressable (val);
-
- if (is_inout)
- ninout++;
- }
-
- ninputs += ninout;
- if (ninputs + noutputs > MAX_RECOG_OPERANDS)
- {
- error ("more than %d operands in %<asm%>", MAX_RECOG_OPERANDS);
- return;
- }
-
- for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail))
- {
- bool allows_reg, allows_mem;
- const char *constraint;
-
- /* If there's an erroneous arg, emit no insn, because the ASM_INPUT
- would get VOIDmode and that could cause a crash in reload. */
- if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
- return;
-
- constraint = constraints[i + noutputs];
- if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
- constraints, &allows_mem, &allows_reg))
- return;
-
- if (! allows_reg && allows_mem)
- lang_hooks.mark_addressable (TREE_VALUE (tail));
- }
-
- /* Second pass evaluates arguments. */
-
- ninout = 0;
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- {
- tree val = TREE_VALUE (tail);
- tree type = TREE_TYPE (val);
- bool is_inout;
- bool allows_reg;
- bool allows_mem;
- rtx op;
- bool ok;
-
- ok = parse_output_constraint (&constraints[i], i, ninputs,
- noutputs, &allows_mem, &allows_reg,
- &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.
- Make the asm insn write into that, then our caller will copy it to
- the real output operand. Likewise for promoted variables. */
-
- generating_concat_p = 0;
-
- real_output_rtx[i] = NULL_RTX;
- if ((TREE_CODE (val) == INDIRECT_REF
- && allows_mem)
- || (DECL_P (val)
- && (allows_mem || REG_P (DECL_RTL (val)))
- && ! (REG_P (DECL_RTL (val))
- && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
- || ! allows_reg
- || is_inout)
- {
- op = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
- if (MEM_P (op))
- op = validize_mem (op);
-
- if (! allows_reg && !MEM_P (op))
- error ("output number %d not directly addressable", i);
- if ((! allows_mem && MEM_P (op))
- || GET_CODE (op) == CONCAT)
- {
- real_output_rtx[i] = op;
- op = gen_reg_rtx (GET_MODE (op));
- if (is_inout)
- emit_move_insn (op, real_output_rtx[i]);
- }
- }
- else
- {
- op = assign_temp (type, 0, 0, 1);
- op = validize_mem (op);
- TREE_VALUE (tail) = make_tree (type, op);
- }
- output_rtx[i] = op;
-
- generating_concat_p = old_generating_concat_p;
-
- if (is_inout)
- {
- inout_mode[ninout] = TYPE_MODE (type);
- inout_opnum[ninout++] = i;
- }
-
- if (tree_conflicts_with_clobbers_p (val, &clobbered_regs))
- clobber_conflict_found = 1;
- }
-
- /* Make vectors for the expression-rtx, constraint strings,
- and named operands. */
-
- argvec = rtvec_alloc (ninputs);
- constraintvec = rtvec_alloc (ninputs);
-
- body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
- : GET_MODE (output_rtx[0])),
- ggc_strdup (TREE_STRING_POINTER (string)),
- empty_string, 0, argvec, constraintvec,
- locus);
-
- MEM_VOLATILE_P (body) = vol;
-
- /* Eval the inputs and put them into ARGVEC.
- Put their constraints into ASM_INPUTs and store in CONSTRAINTS. */
-
- for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
- {
- bool allows_reg, allows_mem;
- const char *constraint;
- tree val, type;
- rtx op;
- bool ok;
-
- constraint = constraints[i + noutputs];
- ok = parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
- constraints, &allows_mem, &allows_reg);
- gcc_assert (ok);
-
- generating_concat_p = 0;
-
- val = TREE_VALUE (tail);
- type = TREE_TYPE (val);
- /* EXPAND_INITIALIZER will not generate code for valid initializer
- constants, but will still generate code for other types of operand.
- This is the behavior we want for constant constraints. */
- op = expand_expr (val, NULL_RTX, VOIDmode,
- allows_reg ? EXPAND_NORMAL
- : allows_mem ? EXPAND_MEMORY
- : EXPAND_INITIALIZER);
-
- /* Never pass a CONCAT to an ASM. */
- if (GET_CODE (op) == CONCAT)
- op = force_reg (GET_MODE (op), op);
- else if (MEM_P (op))
- op = validize_mem (op);
-
- if (asm_operand_ok (op, constraint) <= 0)
- {
- if (allows_reg && TYPE_MODE (type) != BLKmode)
- op = force_reg (TYPE_MODE (type), op);
- else if (!allows_mem)
- warning (0, "asm operand %d probably doesn%'t match constraints",
- i + noutputs);
- else if (MEM_P (op))
- {
- /* We won't recognize either volatile memory or memory
- with a queued address as available a memory_operand
- at this point. Ignore it: clearly this *is* a memory. */
- }
- else
- {
- warning (0, "use of memory input without lvalue in "
- "asm operand %d is deprecated", i + noutputs);
-
- if (CONSTANT_P (op))
- {
- rtx mem = force_const_mem (TYPE_MODE (type), op);
- if (mem)
- op = validize_mem (mem);
- else
- op = force_reg (TYPE_MODE (type), op);
- }
- if (REG_P (op)
- || GET_CODE (op) == SUBREG
- || GET_CODE (op) == CONCAT)
- {
- tree qual_type = build_qualified_type (type,
- (TYPE_QUALS (type)
- | TYPE_QUAL_CONST));
- rtx memloc = assign_temp (qual_type, 1, 1, 1);
- memloc = validize_mem (memloc);
- emit_move_insn (memloc, op);
- op = memloc;
- }
- }
- }
-
- generating_concat_p = old_generating_concat_p;
- ASM_OPERANDS_INPUT (body, i) = op;
-
- /* APPLE LOCAL begin CW asm blocks */
- /* Crude way of detecting an entry static label declaration
- (See iasm_entry). Make this a local symbol. */
- if (i == 0 && !TREE_CHAIN (tail)
- && strcmp (TREE_STRING_POINTER (string), "%0:") == 0
- && GET_CODE (op) == SYMBOL_REF)
- {
- SYMBOL_REF_FLAGS (op) |= SYMBOL_FLAG_LOCAL;
- SYMBOL_REF_FLAGS (op) &= ~SYMBOL_FLAG_EXTERNAL;
- }
- /* APPLE LOCAL end CW asm blocks */
-
- ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
- = gen_rtx_ASM_INPUT (TYPE_MODE (type),
- ggc_strdup (constraints[i + noutputs]));
-
- if (tree_conflicts_with_clobbers_p (val, &clobbered_regs))
- clobber_conflict_found = 1;
- }
-
- /* Protect all the operands from the queue now that they have all been
- evaluated. */
-
- generating_concat_p = 0;
-
- /* For in-out operands, copy output rtx to input rtx. */
- for (i = 0; i < ninout; i++)
- {
- int j = inout_opnum[i];
- char buffer[16];
-
- ASM_OPERANDS_INPUT (body, ninputs - ninout + i)
- = output_rtx[j];
-
- sprintf (buffer, "%d", j);
- ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, ninputs - ninout + i)
- = gen_rtx_ASM_INPUT (inout_mode[i], ggc_strdup (buffer));
- }
-
- /* APPLE LOCAL begin CW asm blocks */
- for (tail = uses; tail; tail = TREE_CHAIN (tail))
- nuses++;
- /* APPLE LOCAL end CW asm blocks */
- generating_concat_p = old_generating_concat_p;
-
- /* Now, for each output, construct an rtx
- (set OUTPUT (asm_operands INSN OUTPUTCONSTRAINT OUTPUTNUMBER
- ARGVEC CONSTRAINTS OPNAMES))
- If there is more than one, put them inside a PARALLEL. */
-
- /* APPLE LOCAL CW asm blocks */
- if (noutputs == 1 && nclobbers == 0 && nuses == 0)
- {
- ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]);
- emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
- }
-
- /* APPLE LOCAL CW asm blocks */
- else if (noutputs == 0 && nclobbers == 0 && nuses == 0)
- {
- /* No output operands: put in a raw ASM_OPERANDS rtx. */
- emit_insn (body);
- }
-
- else
- {
- rtx obody = body;
- int num = noutputs;
-
- if (num == 0)
- num = 1;
-
- /* APPLE LOCAL CW asm blocks */
- body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num + nclobbers + nuses));
-
- /* For each output operand, store a SET. */
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- {
- XVECEXP (body, 0, i)
- = gen_rtx_SET (VOIDmode,
- output_rtx[i],
- gen_rtx_ASM_OPERANDS
- (GET_MODE (output_rtx[i]),
- 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 there are no outputs (but there are some clobbers)
- store the bare ASM_OPERANDS into the PARALLEL. */
-
- if (i == 0)
- XVECEXP (body, 0, i++) = obody;
-
- /* Store (clobber REG) for each clobbered register specified. */
-
- for (tail = clobbers; tail; tail = TREE_CHAIN (tail))
- {
- const char *regname = TREE_STRING_POINTER (TREE_VALUE (tail));
- int j = decode_reg_name (regname);
- rtx clobbered_reg;
-
- if (j < 0)
- {
- if (j == -3) /* `cc', which is not a register */
- continue;
-
- if (j == -4) /* `memory', don't cache memory across asm */
- {
- XVECEXP (body, 0, i++)
- = gen_rtx_CLOBBER (VOIDmode,
- gen_rtx_MEM
- (BLKmode,
- gen_rtx_SCRATCH (VOIDmode)));
- continue;
- }
-
- /* Ignore unknown register, error already signaled. */
- continue;
- }
-
- /* Use QImode since that's guaranteed to clobber just one reg. */
- clobbered_reg = gen_rtx_REG (QImode, j);
-
- /* Do sanity check for overlap between clobbers and respectively
- input and outputs that hasn't been handled. Such overlap
- should have been detected and reported above. */
- if (!clobber_conflict_found)
- {
- int opno;
-
- /* We test the old body (obody) contents to avoid tripping
- over the under-construction body. */
- for (opno = 0; opno < noutputs; opno++)
- if (reg_overlap_mentioned_p (clobbered_reg, output_rtx[opno]))
- internal_error ("asm clobber conflict with output operand");
-
- for (opno = 0; opno < ninputs - ninout; opno++)
- if (reg_overlap_mentioned_p (clobbered_reg,
- ASM_OPERANDS_INPUT (obody, opno)))
- internal_error ("asm clobber conflict with input operand");
- }
-
- XVECEXP (body, 0, i++)
- = gen_rtx_CLOBBER (VOIDmode, clobbered_reg);
- }
-
- /* APPLE LOCAL begin CW asm blocks */
- for (tail = uses; tail; tail = TREE_CHAIN (tail))
- {
- int regno;
- rtx rtx_reg;
- const char *use_regname = TREE_STRING_POINTER (TREE_VALUE (tail));
- regno = decode_reg_name (use_regname);
- rtx_reg = gen_rtx_REG (QImode, regno);
- XVECEXP (body, 0, i++) = gen_rtx_USE (VOIDmode, rtx_reg);
- }
- /* APPLE LOCAL end CW asm blocks */
- emit_insn (body);
- }
-
- /* For any outputs that needed reloading into registers, spill them
- back to where they belong. */
- for (i = 0; i < noutputs; ++i)
- if (real_output_rtx[i])
- emit_move_insn (real_output_rtx[i], output_rtx[i]);
-
- free_temp_slots ();
-}
-
-void
-expand_asm_expr (tree exp)
-{
- int noutputs, i;
- tree outputs, tail;
- tree *o;
-
- if (ASM_INPUT_P (exp))
- {
- expand_asm (ASM_STRING (exp), ASM_VOLATILE_P (exp));
- return;
- }
-
- outputs = ASM_OUTPUTS (exp);
- noutputs = list_length (outputs);
- /* o[I] is the place that output number I should be written. */
- o = (tree *) alloca (noutputs * sizeof (tree));
-
- /* Record the contents of OUTPUTS before it is modified. */
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- o[i] = TREE_VALUE (tail);
-
- /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
- OUTPUTS some trees for where the values were actually stored. */
- expand_asm_operands (ASM_STRING (exp), outputs, ASM_INPUTS (exp),
- ASM_CLOBBERS (exp), ASM_VOLATILE_P (exp),
- /* APPLE LOCAL CW asm blocks */
- ASM_USES (exp),
- input_location);
-
- /* Copy all the intermediate outputs into the specified outputs. */
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
- {
- if (o[i] != TREE_VALUE (tail))
- {
- expand_assignment (o[i], TREE_VALUE (tail));
- free_temp_slots ();
-
- /* Restore the original value so that it's correct the next
- time we expand this function. */
- TREE_VALUE (tail) = o[i];
- }
- }
-}
-
-/* A subroutine of expand_asm_operands. Check that all operands have
- the same number of alternatives. Return true if so. */
-
-static bool
-check_operand_nalternatives (tree outputs, tree inputs)
-{
- if (outputs || inputs)
- {
- tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
- int nalternatives
- = n_occurrences (',', TREE_STRING_POINTER (TREE_VALUE (tmp)));
- tree next = inputs;
-
- if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
- {
- error ("too many alternatives in %<asm%>");
- return false;
- }
-
- tmp = outputs;
- while (tmp)
- {
- const char *constraint
- = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tmp)));
-
- if (n_occurrences (',', constraint) != nalternatives)
- {
- error ("operand constraints for %<asm%> differ "
- "in number of alternatives");
- return false;
- }
-
- if (TREE_CHAIN (tmp))
- tmp = TREE_CHAIN (tmp);
- else
- tmp = next, next = 0;
- }
- }
-
- return true;
-}
-
-/* A subroutine of expand_asm_operands. Check that all operand names
- are unique. Return true if so. We rely on the fact that these names
- are identifiers, and so have been canonicalized by get_identifier,
- so all we need are pointer comparisons. */
-
-static bool
-check_unique_operand_names (tree outputs, tree inputs)
-{
- tree i, j;
-
- for (i = outputs; i ; i = TREE_CHAIN (i))
- {
- tree i_name = TREE_PURPOSE (TREE_PURPOSE (i));
- if (! i_name)
- continue;
-
- for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
- if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
- goto failure;
- }
-
- for (i = inputs; i ; i = TREE_CHAIN (i))
- {
- tree i_name = TREE_PURPOSE (TREE_PURPOSE (i));
- if (! i_name)
- continue;
-
- for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
- if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
- goto failure;
- for (j = outputs; j ; j = TREE_CHAIN (j))
- if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
- goto failure;
- }
-
- return true;
-
- failure:
- error ("duplicate asm operand name %qs",
- TREE_STRING_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
- return false;
-}
-
-/* A subroutine of expand_asm_operands. Resolve the names of the operands
- in *POUTPUTS and *PINPUTS to numbers, and replace the name expansions in
- STRING and in the constraints to those numbers. */
-
-tree
-resolve_asm_operand_names (tree string, tree outputs, tree inputs)
-{
- char *buffer;
- char *p;
- const char *c;
- tree t;
-
- check_unique_operand_names (outputs, inputs);
-
- /* Substitute [<name>] in input constraint strings. There should be no
- named operands in output constraints. */
- for (t = inputs; t ; t = TREE_CHAIN (t))
- {
- c = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
- if (strchr (c, '[') != NULL)
- {
- p = buffer = xstrdup (c);
- while ((p = strchr (p, '[')) != NULL)
- p = resolve_operand_name_1 (p, outputs, inputs);
- TREE_VALUE (TREE_PURPOSE (t))
- = build_string (strlen (buffer), buffer);
- free (buffer);
- }
- }
-
- /* Now check for any needed substitutions in the template. */
- c = TREE_STRING_POINTER (string);
- while ((c = strchr (c, '%')) != NULL)
- {
- if (c[1] == '[')
- break;
- else if (ISALPHA (c[1]) && c[2] == '[')
- break;
- else
- {
- c += 1;
- continue;
- }
- }
-
- if (c)
- {
- /* OK, we need to make a copy so we can perform the substitutions.
- Assume that we will not need extra space--we get to remove '['
- and ']', which means we cannot have a problem until we have more
- than 999 operands. */
- buffer = xstrdup (TREE_STRING_POINTER (string));
- p = buffer + (c - TREE_STRING_POINTER (string));
-
- while ((p = strchr (p, '%')) != NULL)
- {
- if (p[1] == '[')
- p += 1;
- else if (ISALPHA (p[1]) && p[2] == '[')
- p += 2;
- else
- {
- p += 1;
- continue;
- }
-
- p = resolve_operand_name_1 (p, outputs, inputs);
- }
-
- string = build_string (strlen (buffer), buffer);
- free (buffer);
- }
-
- return string;
-}
-
-/* A subroutine of resolve_operand_names. P points to the '[' for a
- potential named operand of the form [<name>]. In place, replace
- the name and brackets with a number. Return a pointer to the
- balance of the string after substitution. */
-
-static char *
-resolve_operand_name_1 (char *p, tree outputs, tree inputs)
-{
- char *q;
- int op;
- tree t;
- size_t len;
-
- /* Collect the operand name. */
- q = strchr (p, ']');
- if (!q)
- {
- error ("missing close brace for named operand");
- return strchr (p, '\0');
- }
- len = q - p - 1;
-
- /* Resolve the name to a number. */
- for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
- {
- tree name = TREE_PURPOSE (TREE_PURPOSE (t));
- if (name)
- {
- const char *c = TREE_STRING_POINTER (name);
- if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
- goto found;
- }
- }
- for (t = inputs; t ; t = TREE_CHAIN (t), op++)
- {
- tree name = TREE_PURPOSE (TREE_PURPOSE (t));
- if (name)
- {
- const char *c = TREE_STRING_POINTER (name);
- if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
- goto found;
- }
- }
-
- *q = '\0';
- error ("undefined named operand %qs", p + 1);
- op = 0;
- found:
-
- /* Replace the name with the number. Unfortunately, not all libraries
- get the return value of sprintf correct, so search for the end of the
- generated string by hand. */
- sprintf (p, "%d", op);
- p = strchr (p, '\0');
-
- /* Verify the no extra buffer space assumption. */
- gcc_assert (p <= q);
-
- /* Shift the rest of the buffer down to fill the gap. */
- memmove (p, q + 1, strlen (q + 1) + 1);
-
- return p;
-}
-
-/* Generate RTL to evaluate the expression EXP. */
-
-void
-expand_expr_stmt (tree exp)
-{
- rtx value;
- tree type;
-
- value = expand_expr (exp, const0_rtx, VOIDmode, 0);
- type = TREE_TYPE (exp);
-
- /* If all we do is reference a volatile value in memory,
- copy it to a register to be sure it is actually touched. */
- if (value && MEM_P (value) && TREE_THIS_VOLATILE (exp))
- {
- if (TYPE_MODE (type) == VOIDmode)
- ;
- else if (TYPE_MODE (type) != BLKmode)
- value = copy_to_reg (value);
- else
- {
- rtx lab = gen_label_rtx ();
-
- /* Compare the value with itself to reference it. */
- emit_cmp_and_jump_insns (value, value, EQ,
- expand_normal (TYPE_SIZE (type)),
- BLKmode, 0, lab);
- emit_label (lab);
- }
- }
-
- /* Free any temporaries used to evaluate this expression. */
- free_temp_slots ();
-}
-
-/* Warn if EXP contains any computations whose results are not used.
- Return 1 if a warning is printed; 0 otherwise. LOCUS is the
- (potential) location of the expression. */
-
-int
-warn_if_unused_value (tree exp, location_t locus)
-{
- restart:
- if (TREE_USED (exp) || TREE_NO_WARNING (exp))
- return 0;
-
- /* Don't warn about void constructs. This includes casting to void,
- void function calls, and statement expressions with a final cast
- to void. */
- if (VOID_TYPE_P (TREE_TYPE (exp)))
- return 0;
-
- if (EXPR_HAS_LOCATION (exp))
- locus = EXPR_LOCATION (exp);
-
- switch (TREE_CODE (exp))
- {
- case PREINCREMENT_EXPR:
- case POSTINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case POSTDECREMENT_EXPR:
- case MODIFY_EXPR:
- case INIT_EXPR:
- case TARGET_EXPR:
- case CALL_EXPR:
- case TRY_CATCH_EXPR:
- case WITH_CLEANUP_EXPR:
- case EXIT_EXPR:
- case VA_ARG_EXPR:
- return 0;
-
- case BIND_EXPR:
- /* For a binding, warn if no side effect within it. */
- exp = BIND_EXPR_BODY (exp);
- goto restart;
-
- case SAVE_EXPR:
- exp = TREE_OPERAND (exp, 0);
- goto restart;
-
- case TRUTH_ORIF_EXPR:
- case TRUTH_ANDIF_EXPR:
- /* In && or ||, warn if 2nd operand has no side effect. */
- exp = TREE_OPERAND (exp, 1);
- goto restart;
-
- case COMPOUND_EXPR:
- if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus))
- return 1;
- /* Let people do `(foo (), 0)' without a warning. */
- if (TREE_CONSTANT (TREE_OPERAND (exp, 1)))
- return 0;
- exp = TREE_OPERAND (exp, 1);
- goto restart;
-
- case COND_EXPR:
- /* If this is an expression with side effects, don't warn; this
- case commonly appears in macro expansions. */
- if (TREE_SIDE_EFFECTS (exp))
- return 0;
- goto warn;
-
- case INDIRECT_REF:
- /* Don't warn about automatic dereferencing of references, since
- the user cannot control it. */
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
- {
- exp = TREE_OPERAND (exp, 0);
- goto restart;
- }
- /* Fall through. */
-
- default:
- /* Referencing a volatile value is a side effect, so don't warn. */
- 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 (EXPRESSION_CLASS_P (exp) && TREE_CODE_LENGTH (TREE_CODE (exp)) == 0)
- return 0;
-
- warn:
- warning (0, "%Hvalue computed is not used", &locus);
- return 1;
- }
-}
-
-
-/* Generate RTL to return from the current function, with no value.
- (That is, we do not do anything about returning any value.) */
-
-void
-expand_null_return (void)
-{
- /* If this function was declared to return a value, but we
- didn't, clobber the return registers so that they are not
- propagated live to the rest of the function. */
- clobber_return_register ();
-
- expand_null_return_1 ();
-}
-
-/* Generate RTL to return directly from the current function.
- (That is, we bypass any return value.) */
-
-void
-expand_naked_return (void)
-{
- rtx end_label;
-
- clear_pending_stack_adjust ();
- do_pending_stack_adjust ();
-
- end_label = naked_return_label;
- if (end_label == 0)
- end_label = naked_return_label = gen_label_rtx ();
-
- emit_jump (end_label);
-}
-
-/* Generate RTL to return from the current function, with value VAL. */
-
-static void
-expand_value_return (rtx val)
-{
- /* Copy the value to the return location
- unless it's already there. */
-
- rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
- if (return_reg != val)
- {
- tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
- if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
- {
- int unsignedp = TYPE_UNSIGNED (type);
- enum machine_mode old_mode
- = DECL_MODE (DECL_RESULT (current_function_decl));
- enum machine_mode mode
- = promote_mode (type, old_mode, &unsignedp, 1);
-
- if (mode != old_mode)
- val = convert_modes (mode, old_mode, val, unsignedp);
- }
- if (GET_CODE (return_reg) == PARALLEL)
- emit_group_load (return_reg, val, type, int_size_in_bytes (type));
- else
- emit_move_insn (return_reg, val);
- }
-
- expand_null_return_1 ();
-}
-
-/* Output a return with no value. */
-
-static void
-expand_null_return_1 (void)
-{
- clear_pending_stack_adjust ();
- do_pending_stack_adjust ();
- emit_jump (return_label);
-}
-
-/* Generate RTL to evaluate the expression RETVAL and return it
- from the current function. */
-
-void
-expand_return (tree retval)
-{
- rtx result_rtl;
- rtx val = 0;
- tree retval_rhs;
-
- /* If function wants no value, give it none. */
- if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
- {
- expand_normal (retval);
- expand_null_return ();
- return;
- }
-
- if (retval == error_mark_node)
- {
- /* Treat this like a return of no value from a function that
- returns a value. */
- expand_null_return ();
- return;
- }
- else if ((TREE_CODE (retval) == MODIFY_EXPR
- || TREE_CODE (retval) == INIT_EXPR)
- && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
- retval_rhs = TREE_OPERAND (retval, 1);
- else
- retval_rhs = retval;
-
- result_rtl = DECL_RTL (DECL_RESULT (current_function_decl));
-
- /* If we are returning the RESULT_DECL, then the value has already
- been stored into it, so we don't have to do anything special. */
- if (TREE_CODE (retval_rhs) == RESULT_DECL)
- expand_value_return (result_rtl);
-
- /* If the result is an aggregate that is being returned in one (or more)
- registers, load the registers here. The compiler currently can't handle
- copying a BLKmode value into registers. We could put this code in a
- more general area (for use by everyone instead of just function
- call/return), but until this feature is generally usable it is kept here
- (and in expand_call). */
-
- else if (retval_rhs != 0
- && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
- && REG_P (result_rtl))
- {
- int i;
- unsigned HOST_WIDE_INT bitpos, xbitpos;
- unsigned HOST_WIDE_INT padding_correction = 0;
- unsigned HOST_WIDE_INT bytes
- = int_size_in_bytes (TREE_TYPE (retval_rhs));
- 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_reg, src = NULL_RTX, dst = NULL_RTX;
- rtx result_val = expand_normal (retval_rhs);
- enum machine_mode tmpmode, result_reg_mode;
-
- if (bytes == 0)
- {
- expand_null_return ();
- return;
- }
-
- /* If the structure doesn't take up a whole number of words, see
- whether the register value should be padded on the left or on
- the right. Set PADDING_CORRECTION to the number of padding
- bits needed on the left side.
-
- In most ABIs, the structure will be returned at the least end of
- the register, which translates to right padding on little-endian
- targets and left padding on big-endian targets. The opposite
- holds if the structure is returned at the most significant
- end of the register. */
- if (bytes % UNITS_PER_WORD != 0
- && (targetm.calls.return_in_msb (TREE_TYPE (retval_rhs))
- ? !BYTES_BIG_ENDIAN
- : BYTES_BIG_ENDIAN))
- padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
- * BITS_PER_UNIT));
-
- /* Copy the structure BITSIZE bits at a time. */
- for (bitpos = 0, xbitpos = padding_correction;
- bitpos < bytes * BITS_PER_UNIT;
- bitpos += bitsize, xbitpos += bitsize)
- {
- /* We need a new destination pseudo each time xbitpos is
- on a word boundary and when xbitpos == padding_correction
- (the first time through). */
- if (xbitpos % BITS_PER_WORD == 0
- || xbitpos == padding_correction)
- {
- /* Generate an appropriate register. */
- dst = gen_reg_rtx (word_mode);
- result_pseudos[xbitpos / BITS_PER_WORD] = dst;
-
- /* Clear the destination before we move anything into it. */
- emit_move_insn (dst, CONST0_RTX (GET_MODE (dst)));
- }
-
- /* We need a new source operand each time bitpos is on a word
- boundary. */
- if (bitpos % BITS_PER_WORD == 0)
- src = operand_subword_force (result_val,
- bitpos / BITS_PER_WORD,
- BLKmode);
-
- /* Use bitpos for the source extraction (left justified) and
- xbitpos for the destination store (right justified). */
- store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode,
- extract_bit_field (src, bitsize,
- bitpos % BITS_PER_WORD, 1,
- /* APPLE LOCAL begin 6020402 */
- NULL_RTX, word_mode, word_mode),
- NULL_TREE);
- /* APPLE LOCAL end 6020402 */
- }
-
- tmpmode = GET_MODE (result_rtl);
- if (tmpmode == BLKmode)
- {
- /* Find the smallest integer mode large enough to hold the
- entire structure and use that mode instead of BLKmode
- on the USE insn for the return register. */
- for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
- tmpmode != VOIDmode;
- tmpmode = GET_MODE_WIDER_MODE (tmpmode))
- /* Have we found a large enough mode? */
- if (GET_MODE_SIZE (tmpmode) >= bytes)
- break;
-
- /* A suitable mode should have been found. */
- gcc_assert (tmpmode != VOIDmode);
-
- PUT_MODE (result_rtl, tmpmode);
- }
-
- if (GET_MODE_SIZE (tmpmode) < GET_MODE_SIZE (word_mode))
- result_reg_mode = word_mode;
- else
- result_reg_mode = tmpmode;
- result_reg = gen_reg_rtx (result_reg_mode);
-
- for (i = 0; i < n_regs; i++)
- emit_move_insn (operand_subword (result_reg, i, 0, result_reg_mode),
- result_pseudos[i]);
-
- if (tmpmode != result_reg_mode)
- result_reg = gen_lowpart (tmpmode, result_reg);
-
- expand_value_return (result_reg);
- }
- else if (retval_rhs != 0
- && !VOID_TYPE_P (TREE_TYPE (retval_rhs))
- && (REG_P (result_rtl)
- || (GET_CODE (result_rtl) == PARALLEL)))
- {
- /* Calculate the return value into a temporary (usually a pseudo
- reg). */
- tree ot = TREE_TYPE (DECL_RESULT (current_function_decl));
- tree nt = build_qualified_type (ot, TYPE_QUALS (ot) | TYPE_QUAL_CONST);
-
- val = assign_temp (nt, 0, 0, 1);
- val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
- val = force_not_mem (val);
- /* Return the calculated value. */
- expand_value_return (val);
- }
- else
- {
- /* No hard reg used; calculate value into hard return reg. */
- expand_expr (retval, const0_rtx, VOIDmode, 0);
- expand_value_return (result_rtl);
- }
-}
-
-/* Given a pointer to a BLOCK node return nonzero if (and only if) the node
- in question represents the outermost pair of curly braces (i.e. the "body
- block") of a function or method.
-
- For any BLOCK node representing a "body block" of a function or method, the
- BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which
- represents the outermost (function) scope for the function or method (i.e.
- the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of
- *that* node in turn will point to the relevant FUNCTION_DECL node. */
-
-int
-is_body_block (tree stmt)
-{
- if (lang_hooks.no_body_blocks)
- return 0;
-
- if (TREE_CODE (stmt) == BLOCK)
- {
- tree parent = BLOCK_SUPERCONTEXT (stmt);
-
- if (parent && TREE_CODE (parent) == BLOCK)
- {
- tree grandparent = BLOCK_SUPERCONTEXT (parent);
-
- if (grandparent && TREE_CODE (grandparent) == FUNCTION_DECL)
- return 1;
- }
- }
-
- return 0;
-}
-
-/* Emit code to restore vital registers at the beginning of a nonlocal goto
- handler. */
-static void
-expand_nl_goto_receiver (void)
-{
- /* 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));
-
- /* 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));
-
-#ifdef HAVE_nonlocal_goto
- if (! HAVE_nonlocal_goto)
-#endif
- /* First adjust our frame pointer to its actual value. It was
- previously set to the start of the virtual area corresponding to
- the stacked variables when we branched here and now needs to be
- adjusted to the actual hardware fp value.
-
- Assignments are to virtual registers are converted by
- instantiate_virtual_regs into the corresponding assignment
- to the underlying register (fp in this case) that makes
- the original assignment true.
- So the following insn will actually be
- decrementing fp by STARTING_FRAME_OFFSET. */
- emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
-
-#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- if (fixed_regs[ARG_POINTER_REGNUM])
- {
-#ifdef ELIMINABLE_REGS
- /* If the argument pointer can be eliminated in favor of the
- frame pointer, we don't need to restore it. We assume here
- that if such an elimination is present, it can always be used.
- This is the case on all known machines; if we don't make this
- assumption, we do unnecessary saving on many machines. */
- static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
- if (elim_regs[i].from == ARG_POINTER_REGNUM
- && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
- break;
-
- if (i == ARRAY_SIZE (elim_regs))
-#endif
- {
- /* 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)));
- }
- }
-#endif
-
-#ifdef HAVE_nonlocal_goto_receiver
- if (HAVE_nonlocal_goto_receiver)
- 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, ""));
-}
-
-/* Generate RTL for the automatic variable declaration DECL.
- (Other kinds of declarations are simply ignored if seen here.) */
-
-void
-expand_decl (tree decl)
-{
- tree type;
-
- type = TREE_TYPE (decl);
-
- /* For a CONST_DECL, set mode, alignment, and sizes from those of the
- type in case this node is used in a reference. */
- if (TREE_CODE (decl) == CONST_DECL)
- {
- DECL_MODE (decl) = TYPE_MODE (type);
- DECL_ALIGN (decl) = TYPE_ALIGN (type);
- DECL_SIZE (decl) = TYPE_SIZE (type);
- DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (type);
- return;
- }
-
- /* Otherwise, only automatic variables need any expansion done. Static and
- external variables, and external functions, will be handled by
- `assemble_variable' (called from finish_decl). TYPE_DECL requires
- nothing. PARM_DECLs are handled in `assign_parms'. */
- if (TREE_CODE (decl) != VAR_DECL)
- return;
-
- if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
- return;
-
- /* Create the RTL representation for the variable. */
-
- if (type == error_mark_node)
- SET_DECL_RTL (decl, gen_rtx_MEM (BLKmode, const0_rtx));
-
- else if (DECL_SIZE (decl) == 0)
- /* Variable with incomplete type. */
- {
- rtx x;
- if (DECL_INITIAL (decl) == 0)
- /* Error message was already done; now avoid a crash. */
- x = gen_rtx_MEM (BLKmode, const0_rtx);
- else
- /* An initializer is going to decide the size of this array.
- Until we know the size, represent its address with a reg. */
- x = gen_rtx_MEM (BLKmode, gen_reg_rtx (Pmode));
-
- set_mem_attributes (x, decl, 1);
- SET_DECL_RTL (decl, x);
- }
- else if (use_register_for_decl (decl))
- {
- /* Automatic variable that can go in a register. */
- int unsignedp = TYPE_UNSIGNED (type);
- enum machine_mode reg_mode
- = promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
-
- SET_DECL_RTL (decl, gen_reg_rtx (reg_mode));
-
- /* 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))));
- }
- }
-
- else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
- && ! (flag_stack_check && ! STACK_CHECK_BUILTIN
- && 0 < compare_tree_int (DECL_SIZE_UNIT (decl),
- STACK_CHECK_MAX_VAR_SIZE)))
- {
- /* Variable of fixed size that goes on the stack. */
- rtx oldaddr = 0;
- rtx addr;
- rtx x;
-
- /* If we previously made RTL for this decl, it must be an array
- whose size was determined by the initializer.
- The old address was a register; set that register now
- to the proper address. */
- if (DECL_RTL_SET_P (decl))
- {
- gcc_assert (MEM_P (DECL_RTL (decl)));
- gcc_assert (REG_P (XEXP (DECL_RTL (decl), 0)));
- oldaddr = XEXP (DECL_RTL (decl), 0);
- }
-
- /* Set alignment we actually gave this decl. */
- DECL_ALIGN (decl) = (DECL_MODE (decl) == BLKmode ? BIGGEST_ALIGNMENT
- : GET_MODE_BITSIZE (DECL_MODE (decl)));
- DECL_USER_ALIGN (decl) = 0;
-
- x = assign_temp (decl, 1, 1, 1);
- set_mem_attributes (x, decl, 1);
- SET_DECL_RTL (decl, x);
-
- if (oldaddr)
- {
- addr = force_operand (XEXP (DECL_RTL (decl), 0), oldaddr);
- if (addr != oldaddr)
- emit_move_insn (oldaddr, addr);
- }
- }
- else
- /* Dynamic-size object: must push space on the stack. */
- {
- rtx address, size, x;
-
- /* Record the stack pointer on entry to block, if have
- not already done so. */
- do_pending_stack_adjust ();
-
- /* Compute the variable's size, in bytes. This will expand any
- needed SAVE_EXPRs for the first time. */
- size = expand_normal (DECL_SIZE_UNIT (decl));
- free_temp_slots ();
-
- /* Allocate space on the stack for the variable. Note that
- DECL_ALIGN says how the variable is to be aligned and we
- cannot use it to conclude anything about the alignment of
- the size. */
- address = allocate_dynamic_stack_space (size, NULL_RTX,
- TYPE_ALIGN (TREE_TYPE (decl)));
-
- /* Reference the variable indirect through that rtx. */
- x = gen_rtx_MEM (DECL_MODE (decl), address);
- set_mem_attributes (x, decl, 1);
- SET_DECL_RTL (decl, x);
-
-
- /* Indicate the alignment we actually gave this variable. */
-#ifdef STACK_BOUNDARY
- DECL_ALIGN (decl) = STACK_BOUNDARY;
-#else
- DECL_ALIGN (decl) = BIGGEST_ALIGNMENT;
-#endif
- DECL_USER_ALIGN (decl) = 0;
- }
-}
-
-/* Emit code to save the current value of stack. */
-rtx
-expand_stack_save (void)
-{
- rtx ret = NULL_RTX;
-
- do_pending_stack_adjust ();
- emit_stack_save (SAVE_BLOCK, &ret, NULL_RTX);
- return ret;
-}
-
-/* Emit code to restore the current value of stack. */
-void
-expand_stack_restore (tree var)
-{
- rtx sa = DECL_RTL (var);
-
- emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX);
-}
-
-/* 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. */
-
-void
-expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
- tree decl_elts)
-{
- rtx x;
- tree t;
-
- /* If any of the elements are addressable, so is the entire union. */
- for (t = decl_elts; t; t = TREE_CHAIN (t))
- if (TREE_ADDRESSABLE (TREE_VALUE (t)))
- {
- TREE_ADDRESSABLE (decl) = 1;
- break;
- }
-
- expand_decl (decl);
- x = DECL_RTL (decl);
-
- /* Go through the elements, assigning RTL to each. */
- for (t = decl_elts; t; t = TREE_CHAIN (t))
- {
- 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. */
- if (TREE_USED (decl_elt))
- TREE_USED (decl) = 1;
-
- /* Propagate the union's alignment to the elements. */
- DECL_ALIGN (decl_elt) = DECL_ALIGN (decl);
- DECL_USER_ALIGN (decl_elt) = DECL_USER_ALIGN (decl);
-
- /* If the element has BLKmode and the union doesn't, the union is
- aligned such that the element doesn't need to have BLKmode, so
- change the element's mode to the appropriate one for its size. */
- if (mode == BLKmode && DECL_MODE (decl) != BLKmode)
- DECL_MODE (decl_elt) = mode
- = mode_for_size_tree (DECL_SIZE (decl_elt), MODE_INT, 1);
-
- 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
- {
- gcc_assert (REG_P (x));
- decl_rtl = gen_lowpart_SUBREG (mode, x);
- }
- SET_DECL_RTL (decl_elt, decl_rtl);
- }
-}
-
-/* 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. The bounds on the case range, LOW and HIGH,
- are converted to case's index type TYPE. */
-
-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))
- {
- /* 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. Make sure to drop overflow flags. */
- r = ggc_alloc (sizeof (struct case_node));
- 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),
- TREE_INT_CST_HIGH (high));
- r->code_label = label;
- r->parent = r->left = NULL;
- r->right = head;
- return r;
-}
-
-/* Maximum number of case bit tests. */
-#define MAX_CASE_BIT_TESTS 3
-
-/* 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 \
- != CODE_FOR_nothing)
-#endif
-
-
-/* A case_bit_test represents a set of case nodes that may be
- selected from using a bit-wise comparison. HI and LO hold
- the integer to be tested against, LABEL contains the label
- to jump to upon success and BITS counts the number of case
- nodes handled by this test, typically the number of bits
- set in HI:LO. */
-
-struct case_bit_test
-{
- HOST_WIDE_INT hi;
- HOST_WIDE_INT lo;
- rtx label;
- int bits;
-};
-
-/* Determine whether "1 << x" is relatively cheap in word_mode. */
-
-static
-bool lshift_cheap_p (void)
-{
- static bool init = false;
- static bool cheap = true;
-
- if (!init)
- {
- rtx reg = gen_rtx_REG (word_mode, 10000);
- int cost = rtx_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg), SET);
- cheap = cost < COSTS_N_INSNS (3);
- init = true;
- }
-
- return cheap;
-}
-
-/* Comparison function for qsort to order bit tests by decreasing
- number of case nodes, i.e. the node with the most cases gets
- tested first. */
-
-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;
-
- if (d2->bits != d1->bits)
- return d2->bits - d1->bits;
-
- /* Stabilize the sort. */
- return CODE_LABEL_NUMBER (d2->label) - CODE_LABEL_NUMBER (d1->label);
-}
-
-/* Expand a switch statement by a short sequence of bit-wise
- comparisons. "switch(x)" is effectively converted into
- "if ((1 << (x-MINVAL)) & CST)" where CST and MINVAL are
- integer constants.
-
- INDEX_EXPR is the value being switched on, which is of
- type INDEX_TYPE. MINVAL is the lowest case value of in
- the case nodes, of INDEX_TYPE type, and RANGE is highest
- value minus MINVAL, also of type INDEX_TYPE. NODES is
- the set of case nodes, and DEFAULT_LABEL is the label to
- branch to should none of the cases match.
-
- There *MUST* be MAX_CASE_BIT_TESTS or less unique case
- node targets. */
-
-static void
-emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
- tree range, case_node_ptr nodes, rtx default_label)
-{
- struct case_bit_test test[MAX_CASE_BIT_TESTS];
- enum machine_mode mode;
- rtx expr, index, label;
- unsigned int i,j,lo,hi;
- struct case_node *n;
- unsigned int count;
-
- count = 0;
- for (n = nodes; n; n = n->right)
- {
- label = label_rtx (n->code_label);
- for (i = 0; i < count; i++)
- if (label == test[i].label)
- break;
-
- if (i == count)
- {
- 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);
- 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);
- else
- test[i].lo |= (HOST_WIDE_INT) 1 << j;
- }
-
- qsort (test, count, sizeof(*test), case_bit_test_cmp);
-
- index_expr = fold_build2 (MINUS_EXPR, index_type,
- fold_convert (index_type, index_expr),
- fold_convert (index_type, minval));
- index = expand_normal (index_expr);
- do_pending_stack_adjust ();
-
- mode = TYPE_MODE (index_type);
- expr = expand_normal (range);
- 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,
- index, NULL_RTX, 1, OPTAB_WIDEN);
-
- for (i = 0; i < count; i++)
- {
- expr = immed_double_const (test[i].lo, test[i].hi, word_mode);
- expr = expand_binop (word_mode, and_optab, index, expr,
- NULL_RTX, 1, OPTAB_WIDEN);
- emit_cmp_and_jump_insns (expr, const0_rtx, NE, NULL_RTX,
- word_mode, 1, test[i].label);
- }
-
- emit_jump (default_label);
-}
-
-#ifndef HAVE_casesi
-#define HAVE_casesi 0
-#endif
-
-#ifndef HAVE_tablejump
-#define HAVE_tablejump 0
-#endif
-
-/* Terminate a case (Pascal/Ada) or switch (C) statement
- in which ORIG_INDEX is the expression to be tested.
- If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
- type as given in the source before any compiler conversions.
- Generate the code to test it and jump to the right place. */
-
-void
-expand_case (tree exp)
-{
- tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
- rtx default_label = 0;
- struct case_node *n;
- unsigned int count, uniq;
- rtx index;
- rtx table_label;
- int ncases;
- rtx *labelvec;
- int i, fail;
- rtx before_case, end, lab;
-
- tree vec = SWITCH_LABELS (exp);
- tree orig_type = TREE_TYPE (exp);
- tree index_expr = SWITCH_COND (exp);
- tree index_type = TREE_TYPE (index_expr);
- int unsignedp = TYPE_UNSIGNED (index_type);
-
- /* The insn after which the case dispatch should finally
- be emitted. Zero for a dummy. */
- rtx start;
-
- /* A list of case labels; it is first built as a list and it may then
- be rearranged into a nearly balanced binary tree. */
- struct case_node *case_list = 0;
-
- /* Label to jump to if no case matches. */
- tree default_label_decl;
-
- /* APPLE LOCAL ARM switch tables 6288519 */
- bool have_casesi;
- /* The switch body is lowered in gimplify.c, we should never have
- switches with a non-NULL SWITCH_BODY here. */
- gcc_assert (!SWITCH_BODY (exp));
- gcc_assert (SWITCH_LABELS (exp));
-
- do_pending_stack_adjust ();
-
- /* An ERROR_MARK occurs for various reasons including invalid data type. */
- if (index_type != error_mark_node)
- {
- tree elt;
- bitmap label_bitmap;
-
- /* 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);
-
- for (i = TREE_VEC_LENGTH (vec) - 1; --i >= 0; )
- {
- tree low, high;
- elt = TREE_VEC_ELT (vec, i);
-
- low = CASE_LOW (elt);
- gcc_assert (low);
- high = CASE_HIGH (elt);
-
- /* Discard empty ranges. */
- if (high && INT_CST_LT (high, low))
- continue;
-
- case_list = add_case_node (case_list, index_type, low, high,
- CASE_LABEL (elt));
- }
-
-
- before_case = start = get_last_insn ();
- default_label = label_rtx (default_label_decl);
-
- /* 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)
- {
- /* Count the elements and track the largest and smallest
- of them (treating them as signed even if they are not). */
- if (count++ == 0)
- {
- minval = n->low;
- maxval = n->high;
- }
- else
- {
- if (INT_CST_LT (n->low, minval))
- minval = n->low;
- if (INT_CST_LT (maxval, n->high))
- maxval = n->high;
- }
- /* A range counts double, since it requires two compares. */
- if (! tree_int_cst_equal (n->low, n->high))
- count++;
-
- /* If we have not seen this label yet, then increase the
- number of unique case node targets seen. */
- lab = label_rtx (n->code_label);
- if (!bitmap_bit_p (label_bitmap, CODE_LABEL_NUMBER (lab)))
- {
- bitmap_set_bit (label_bitmap, CODE_LABEL_NUMBER (lab));
- uniq++;
- }
- }
-
- 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)
- {
- emit_jump (default_label);
- return;
- }
-
- /* Compute span of values. */
- range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
-
- /* APPLE LOCAL ARM switch tables 6288519 */
- have_casesi = HAVE_casesi;
- /* 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. */
- 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,
- we can optimize away the subtraction. */
- if (compare_tree_int (minval, 0) > 0
- && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
- {
- minval = build_int_cst (index_type, 0);
- range = maxval;
- }
- emit_case_bit_tests (index_type, index_expr, minval, range,
- case_list, default_label);
- }
-
- /* If range of values is much bigger than number of values,
- make a sequence of conditional branches instead of a dispatch.
- If the switch-index is a constant, do it this way
- because we can optimize it. */
-
- else if (count < case_values_threshold ()
- || compare_tree_int (range,
- (optimize_size ? 3 : 10) * count) > 0
- /* RANGE may be signed, and really large ranges will show up
- as negative numbers. */
- || compare_tree_int (range, 0) < 0
-/* APPLE LOCAL begin ARM compact switch tables */
-#if !defined(ASM_OUTPUT_ADDR_DIFF_ELT) && !defined(ASM_OUTPUT_ADDR_DIFF_VEC)
- || flag_pic
-#endif
-/* APPLE LOCAL end ARM compact switch tables */
- || !flag_jump_tables
- || TREE_CONSTANT (index_expr)
- /* If neither casesi or tablejump is available, we can
- only go this way. */
- /* APPLE LOCAL ARM switch tables 6288519 */
- || (!have_casesi && !HAVE_tablejump))
- {
- index = expand_normal (index_expr);
-
- /* If the index is a short or char that we do not have
- an insn to handle comparisons directly, convert it to
- a full integer now, rather than letting each comparison
- generate the conversion. */
-
- if (GET_MODE_CLASS (GET_MODE (index)) == MODE_INT
- && ! have_insn_for (COMPARE, GET_MODE (index)))
- {
- enum machine_mode wider_mode;
- for (wider_mode = GET_MODE (index); wider_mode != VOIDmode;
- wider_mode = GET_MODE_WIDER_MODE (wider_mode))
- if (have_insn_for (COMPARE, wider_mode))
- {
- index = convert_to_mode (wider_mode, index, unsignedp);
- break;
- }
- }
-
- do_pending_stack_adjust ();
-
- if (MEM_P (index))
- index = copy_to_reg (index);
-
- /* 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 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. */
-
- 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
- {
- table_label = gen_label_rtx ();
- if (! try_casesi (index_type, index_expr, minval, range,
- table_label, default_label))
- {
- bool ok;
-
- /* Index jumptables from zero for suitable values of
- minval to avoid a subtraction. */
- if (! optimize_size
- && compare_tree_int (minval, 0) > 0
- && compare_tree_int (minval, 3) < 0)
- {
- minval = build_int_cst (index_type, 0);
- range = maxval;
- }
-
- 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. */
-
- ncases = tree_low_cst (range, 0) + 1;
-/* APPLE LOCAL begin ARM compact switch tables */
- /* Add target-specific extra labels. */
- ncases += TARGET_EXTRA_CASES;
-/* APPLE LOCAL end ARM compact switch tables */
- labelvec = alloca (ncases * sizeof (rtx));
- memset (labelvec, 0, ncases * sizeof (rtx));
-
- for (n = case_list; n; n = n->right)
- {
- /* Compute the low and high bounds relative to the minimum
- 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);
- HOST_WIDE_INT i_high
- = 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 ++)
- labelvec[i]
- = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
- }
-
- /* Fill in the gaps with the default. */
- for (i = 0; i < ncases; i++)
- if (labelvec[i] == 0)
- labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label);
-
- /* Output the table. */
- emit_label (table_label);
-
- if (CASE_VECTOR_PC_RELATIVE || flag_pic)
- emit_jump_insn (gen_rtx_ADDR_DIFF_VEC (CASE_VECTOR_MODE,
- gen_rtx_LABEL_REF (Pmode, table_label),
- gen_rtvec_v (ncases, labelvec),
- const0_rtx, const0_rtx));
- else
- emit_jump_insn (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
- gen_rtvec_v (ncases, labelvec)));
-
- /* Record no drop-through after the table. */
- emit_barrier ();
- }
-
- 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 ();
-}
-
-/* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. */
-
-static void
-do_jump_if_equal (enum machine_mode mode, rtx op0, rtx op1, rtx label,
- int unsignedp)
-{
- do_compare_rtx_and_jump (op0, op1, EQ, unsignedp, mode,
- NULL_RTX, NULL_RTX, label);
-}
-
-/* Not all case values are encountered equally. This function
- uses a heuristic to weight case labels, in cases where that
- looks like a reasonable thing to do.
-
- Right now, all we try to guess is text, and we establish the
- following weights:
-
- chars above space: 16
- digits: 16
- default: 12
- space, punct: 8
- tab: 4
- newline: 2
- other "\" chars: 1
- remaining chars: 0
-
- If we find any cases in the switch that are not either -1 or in the range
- of valid ASCII characters, or are control characters other than those
- commonly used with "\", don't treat this switch scanning text.
-
- Return 1 if these nodes are suitable for cost estimation, otherwise
- return 0. */
-
-static int
-estimate_case_costs (case_node_ptr node)
-{
- tree min_ascii = integer_minus_one_node;
- tree max_ascii = build_int_cst (TREE_TYPE (node->high), 127);
- case_node_ptr n;
- int i;
-
- /* If we haven't already made the cost table, make it now. Note that the
- lower bound of the table is -1, not zero. */
-
- if (! cost_table_initialized)
- {
- cost_table_initialized = 1;
-
- for (i = 0; i < 128; i++)
- {
- if (ISALNUM (i))
- COST_TABLE (i) = 16;
- else if (ISPUNCT (i))
- COST_TABLE (i) = 8;
- else if (ISCNTRL (i))
- COST_TABLE (i) = -1;
- }
-
- COST_TABLE (' ') = 8;
- COST_TABLE ('\t') = 4;
- COST_TABLE ('\0') = 4;
- COST_TABLE ('\n') = 2;
- COST_TABLE ('\f') = 1;
- COST_TABLE ('\v') = 1;
- COST_TABLE ('\b') = 1;
- }
-
- /* See if all the case expressions look like text. It is text if the
- constant is >= -1 and the highest constant is <= 127. Do all comparisons
- as signed arithmetic since we don't want to ever access cost_table with a
- value less than -1. Also check that none of the constants in a range
- are strange control characters. */
-
- for (n = node; n; n = n->right)
- {
- if ((INT_CST_LT (n->low, min_ascii)) || INT_CST_LT (max_ascii, n->high))
- return 0;
-
- for (i = (HOST_WIDE_INT) TREE_INT_CST_LOW (n->low);
- i <= (HOST_WIDE_INT) TREE_INT_CST_LOW (n->high); i++)
- if (COST_TABLE (i) < 0)
- return 0;
- }
-
- /* All interesting values are within the range of interesting
- ASCII characters. */
- return 1;
-}
-
-/* Take an ordered list of case nodes
- and transform them into a near optimal binary tree,
- on the assumption that any target code selection value is as
- likely as any other.
-
- The transformation is performed by splitting the ordered
- list into two equal sections plus a pivot. The parts are
- then attached to the pivot as left and right branches. Each
- branch is then transformed recursively. */
-
-static void
-balance_case_nodes (case_node_ptr *head, case_node_ptr parent)
-{
- case_node_ptr np;
-
- np = *head;
- if (np)
- {
- int cost = 0;
- int i = 0;
- int ranges = 0;
- case_node_ptr *npp;
- case_node_ptr left;
-
- /* Count the number of entries on branch. Also count the ranges. */
-
- while (np)
- {
- if (!tree_int_cst_equal (np->low, np->high))
- {
- ranges++;
- if (use_cost_table)
- cost += COST_TABLE (TREE_INT_CST_LOW (np->high));
- }
-
- if (use_cost_table)
- cost += COST_TABLE (TREE_INT_CST_LOW (np->low));
-
- i++;
- np = np->right;
- }
-
- if (i > 2)
- {
- /* Split this list if it is long enough for that to help. */
- npp = head;
- left = *npp;
- if (use_cost_table)
- {
- /* Find the place in the list that bisects the list's total cost,
- Here I gets half the total cost. */
- int n_moved = 0;
- i = (cost + 1) / 2;
- while (1)
- {
- /* Skip nodes while their cost does not reach that amount. */
- if (!tree_int_cst_equal ((*npp)->low, (*npp)->high))
- i -= COST_TABLE (TREE_INT_CST_LOW ((*npp)->high));
- i -= COST_TABLE (TREE_INT_CST_LOW ((*npp)->low));
- if (i <= 0)
- break;
- npp = &(*npp)->right;
- n_moved += 1;
- }
- if (n_moved == 0)
- {
- /* Leave this branch lopsided, but optimize left-hand
- side and fill in `parent' fields for right-hand side. */
- np = *head;
- np->parent = parent;
- balance_case_nodes (&np->left, np);
- for (; np->right; np = np->right)
- np->right->parent = np;
- return;
- }
- }
- /* If there are just three nodes, split at the middle one. */
- else if (i == 3)
- npp = &(*npp)->right;
- else
- {
- /* Find the place in the list that bisects the list's total cost,
- where ranges count as 2.
- Here I gets half the total cost. */
- i = (i + ranges + 1) / 2;
- while (1)
- {
- /* Skip nodes while their cost does not reach that amount. */
- if (!tree_int_cst_equal ((*npp)->low, (*npp)->high))
- i--;
- i--;
- if (i <= 0)
- break;
- npp = &(*npp)->right;
- }
- }
- *head = np = *npp;
- *npp = 0;
- np->parent = parent;
- np->left = left;
-
- /* Optimize each of the two split parts. */
- balance_case_nodes (&np->left, np);
- balance_case_nodes (&np->right, np);
- }
- else
- {
- /* Else leave this branch as one level,
- but fill in `parent' fields. */
- np = *head;
- np->parent = parent;
- for (; np->right; np = np->right)
- np->right->parent = np;
- }
- }
-}
-
-/* Search the parent sections of the case node tree
- to see if a test for the lower bound of NODE would be redundant.
- INDEX_TYPE is the type of the index expression.
-
- The instructions to generate the case decision tree are
- output in the same order as nodes are processed so it is
- known that if a parent node checks the range of the current
- node minus one that the current node is bounded at its lower
- span. Thus the test would be redundant. */
-
-static int
-node_has_low_bound (case_node_ptr node, tree index_type)
-{
- tree low_minus_one;
- case_node_ptr pnode;
-
- /* If the lower bound of this node is the lowest value in the index type,
- we need not test it. */
-
- if (tree_int_cst_equal (node->low, TYPE_MIN_VALUE (index_type)))
- return 1;
-
- /* If this node has a left branch, the value at the left must be less
- than that at this node, so it cannot be bounded at the bottom and
- we need not bother testing any further. */
-
- if (node->left)
- return 0;
-
- 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 (! tree_int_cst_lt (low_minus_one, node->low))
- return 0;
-
- for (pnode = node->parent; pnode; pnode = pnode->parent)
- if (tree_int_cst_equal (low_minus_one, pnode->high))
- return 1;
-
- return 0;
-}
-
-/* Search the parent sections of the case node tree
- to see if a test for the upper bound of NODE would be redundant.
- INDEX_TYPE is the type of the index expression.
-
- The instructions to generate the case decision tree are
- output in the same order as nodes are processed so it is
- known that if a parent node checks the range of the current
- node plus one that the current node is bounded at its upper
- span. Thus the test would be redundant. */
-
-static int
-node_has_high_bound (case_node_ptr node, tree index_type)
-{
- tree high_plus_one;
- case_node_ptr pnode;
-
- /* If there is no upper bound, obviously no test is needed. */
-
- if (TYPE_MAX_VALUE (index_type) == NULL)
- return 1;
-
- /* If the upper bound of this node is the highest value in the type
- of the index expression, we need not test against it. */
-
- if (tree_int_cst_equal (node->high, TYPE_MAX_VALUE (index_type)))
- return 1;
-
- /* If this node has a right branch, the value at the right must be greater
- than that at this node, so it cannot be bounded at the top and
- we need not bother testing any further. */
-
- if (node->right)
- return 0;
-
- 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. */
-
- if (! tree_int_cst_lt (node->high, high_plus_one))
- return 0;
-
- for (pnode = node->parent; pnode; pnode = pnode->parent)
- if (tree_int_cst_equal (high_plus_one, pnode->low))
- return 1;
-
- return 0;
-}
-
-/* Search the parent sections of the
- case node tree to see if both tests for the upper and lower
- bounds of NODE would be redundant. */
-
-static int
-node_is_bounded (case_node_ptr node, tree index_type)
-{
- return (node_has_low_bound (node, index_type)
- && node_has_high_bound (node, index_type));
-}
-
-/* Emit step-by-step code to select a case for the value of INDEX.
- The thus generated decision tree follows the form of the
- case-node binary tree NODE, whose nodes represent test conditions.
- INDEX_TYPE is the type of the index of the switch.
-
- Care is taken to prune redundant tests from the decision tree
- by detecting any boundary conditions already checked by
- emitted rtx. (See node_has_high_bound, node_has_low_bound
- and node_is_bounded, above.)
-
- Where the test conditions can be shown to be redundant we emit
- an unconditional jump to the target code. As a further
- optimization, the subordinates of a tree node are examined to
- check for bounded nodes. In this case conditional and/or
- unconditional jumps as a result of the boundary check for the
- current node are arranged to target the subordinates associated
- code for out of bound conditions on the current node.
-
- We can assume that when control reaches the code generated here,
- the index value has already been compared with the parents
- of this node, and determined to be on the same side of each parent
- as this node is. Thus, if this node tests for the value 51,
- and a parent tested for 52, we don't need to consider
- the possibility of a value greater than 51. If another parent
- tests for the value 50, then this node need not test anything. */
-
-static void
-emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
- tree index_type)
-{
- /* If INDEX has an unsigned type, we must make unsigned branches. */
- int unsignedp = TYPE_UNSIGNED (index_type);
- enum machine_mode mode = GET_MODE (index);
- enum machine_mode imode = TYPE_MODE (index_type);
-
- /* Handle indices detected as constant during RTL expansion. */
- if (mode == VOIDmode)
- mode = imode;
-
- /* See if our parents have already tested everything for us.
- If they have, emit an unconditional jump for this node. */
- if (node_is_bounded (node, index_type))
- emit_jump (label_rtx (node->code_label));
-
- else if (tree_int_cst_equal (node->low, node->high))
- {
- /* Node is single valued. First see if the index expression matches
- this node and then check our children, if any. */
-
- do_jump_if_equal (mode, index,
- convert_modes (mode, imode,
- expand_normal (node->low),
- unsignedp),
- label_rtx (node->code_label), unsignedp);
-
- if (node->right != 0 && node->left != 0)
- {
- /* This node has children on both sides.
- Dispatch to one side or the other
- by comparing the index value with this node's value.
- If one subtree is bounded, check that one first,
- so we can avoid real branches in the tree. */
-
- if (node_is_bounded (node->right, index_type))
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- label_rtx (node->right->code_label));
- emit_case_nodes (index, node->left, default_label, index_type);
- }
-
- else if (node_is_bounded (node->left, index_type))
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- LT, NULL_RTX, mode, unsignedp,
- label_rtx (node->left->code_label));
- emit_case_nodes (index, node->right, default_label, index_type);
- }
-
- /* If both children are single-valued cases with no
- children, finish up all the work. This way, we can save
- one ordered comparison. */
- else if (tree_int_cst_equal (node->right->low, node->right->high)
- && node->right->left == 0
- && node->right->right == 0
- && tree_int_cst_equal (node->left->low, node->left->high)
- && node->left->left == 0
- && node->left->right == 0)
- {
- /* Neither node is bounded. First distinguish the two sides;
- then emit the code for one side at a time. */
-
- /* See if the value matches what the right hand side
- wants. */
- do_jump_if_equal (mode, index,
- convert_modes (mode, imode,
- expand_normal (node->right->low),
- unsignedp),
- label_rtx (node->right->code_label),
- unsignedp);
-
- /* See if the value matches what the left hand side
- wants. */
- do_jump_if_equal (mode, index,
- convert_modes (mode, imode,
- expand_normal (node->left->low),
- unsignedp),
- label_rtx (node->left->code_label),
- unsignedp);
- }
-
- else
- {
- /* Neither node is bounded. First distinguish the two sides;
- then emit the code for one side at a time. */
-
- tree test_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- /* See if the value is on the right. */
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- label_rtx (test_label));
-
- /* Value must be on the left.
- Handle the left-hand subtree. */
- emit_case_nodes (index, node->left, default_label, index_type);
- /* If left-hand subtree does nothing,
- go to default. */
- emit_jump (default_label);
-
- /* Code branches here for the right-hand subtree. */
- expand_label (test_label);
- emit_case_nodes (index, node->right, default_label, index_type);
- }
- }
-
- else if (node->right != 0 && node->left == 0)
- {
- /* 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 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))
- {
- if (!node_has_low_bound (node, index_type))
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- LT, NULL_RTX, mode, unsignedp,
- default_label);
- }
-
- emit_case_nodes (index, node->right, default_label, index_type);
- }
- else
- /* We cannot process node->right normally
- since we haven't ruled out the numbers less than
- this node's value. So handle node->right explicitly. */
- do_jump_if_equal (mode, index,
- convert_modes
- (mode, imode,
- expand_normal (node->right->low),
- unsignedp),
- label_rtx (node->right->code_label), unsignedp);
- }
-
- else if (node->right == 0 && node->left != 0)
- {
- /* Just one subtree, on the left. */
- if (node->left->left || node->left->right
- || !tree_int_cst_equal (node->left->low, node->left->high))
- {
- if (!node_has_high_bound (node, index_type))
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- default_label);
- }
-
- emit_case_nodes (index, node->left, default_label, index_type);
- }
- else
- /* We cannot process node->left normally
- since we haven't ruled out the numbers less than
- this node's value. So handle node->left explicitly. */
- do_jump_if_equal (mode, index,
- convert_modes
- (mode, imode,
- expand_normal (node->left->low),
- unsignedp),
- label_rtx (node->left->code_label), unsignedp);
- }
- }
- else
- {
- /* Node is a range. These cases are very similar to those for a single
- value, except that we do not start by testing whether this node
- is the one to branch to. */
-
- if (node->right != 0 && node->left != 0)
- {
- /* Node has subtrees on both sides.
- If the right-hand subtree is bounded,
- test for it first, since we can go straight there.
- Otherwise, we need to make a branch in the control structure,
- then handle the two subtrees. */
- tree test_label = 0;
-
- if (node_is_bounded (node->right, index_type))
- /* Right hand node is fully bounded so we can eliminate any
- testing and branch directly to the target code. */
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- label_rtx (node->right->code_label));
- else
- {
- /* Right hand node requires testing.
- Branch to a label where we will handle it later. */
-
- test_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- label_rtx (test_label));
- }
-
- /* Value belongs to this node or to the left-hand subtree. */
-
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->low),
- unsignedp),
- GE, NULL_RTX, mode, unsignedp,
- label_rtx (node->code_label));
-
- /* Handle the left-hand subtree. */
- emit_case_nodes (index, node->left, default_label, index_type);
-
- /* If right node had to be handled later, do that now. */
-
- if (test_label)
- {
- /* If the left-hand subtree fell through,
- don't let it fall into the right-hand subtree. */
- emit_jump (default_label);
-
- expand_label (test_label);
- emit_case_nodes (index, node->right, default_label, index_type);
- }
- }
-
- else if (node->right != 0 && node->left == 0)
- {
- /* Deal with values to the left of this node,
- if they are possible. */
- if (!node_has_low_bound (node, index_type))
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->low),
- unsignedp),
- LT, NULL_RTX, mode, unsignedp,
- default_label);
- }
-
- /* Value belongs to this node or to the right-hand subtree. */
-
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- LE, NULL_RTX, mode, unsignedp,
- label_rtx (node->code_label));
-
- emit_case_nodes (index, node->right, default_label, index_type);
- }
-
- else if (node->right == 0 && node->left != 0)
- {
- /* Deal with values to the right of this node,
- if they are possible. */
- if (!node_has_high_bound (node, index_type))
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- default_label);
- }
-
- /* Value belongs to this node or to the left-hand subtree. */
-
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->low),
- unsignedp),
- GE, NULL_RTX, mode, unsignedp,
- label_rtx (node->code_label));
-
- emit_case_nodes (index, node->left, default_label, index_type);
- }
-
- else
- {
- /* Node has no children so we check low and high bounds to remove
- redundant tests. Only one of the bounds can exist,
- since otherwise this node is bounded--a case tested already. */
- int high_bound = node_has_high_bound (node, index_type);
- int low_bound = node_has_low_bound (node, index_type);
-
- if (!high_bound && low_bound)
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->high),
- unsignedp),
- GT, NULL_RTX, mode, unsignedp,
- default_label);
- }
-
- else if (!low_bound && high_bound)
- {
- emit_cmp_and_jump_insns (index,
- convert_modes
- (mode, imode,
- expand_normal (node->low),
- unsignedp),
- LT, NULL_RTX, mode, unsignedp,
- default_label);
- }
- else if (!low_bound && !high_bound)
- {
- /* Widen LOW and HIGH to the same width as INDEX. */
- tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
- tree low = build1 (CONVERT_EXPR, type, node->low);
- tree high = build1 (CONVERT_EXPR, type, node->high);
- rtx low_rtx, new_index, new_bound;
-
- /* Instead of doing two branches, emit one unsigned branch for
- (index-low) > (high-low). */
- low_rtx = expand_expr (low, NULL_RTX, mode, EXPAND_NORMAL);
- 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),
- NULL_RTX, mode, EXPAND_NORMAL);
-
- emit_cmp_and_jump_insns (new_index, new_bound, GT, NULL_RTX,
- mode, 1, default_label);
- }
-
- emit_jump (label_rtx (node->code_label));
- }
- }
-}