/* Expands front end tree to back end RTL for GCC
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "rtl.h"
#include "hard-reg-set.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
+#include "fold-const.h"
#include "varasm.h"
#include "stor-layout.h"
#include "tm_p.h"
#include "except.h"
#include "function.h"
#include "insn-config.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
#include "libfuncs.h"
#include "recog.h"
-#include "machmode.h"
#include "diagnostic-core.h"
#include "output.h"
#include "langhooks.h"
#include "predict.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "target.h"
-#include "pointer-set.h"
+#include "cfganal.h"
#include "basic-block.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "pretty-print.h"
#include "params.h"
#include "dumpfile.h"
+#include "builtins.h"
\f
/* Functions and data structures for expanding case statements. */
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, int, tree);
+static void emit_case_nodes (rtx, case_node_ptr, rtx_code_label *, int, tree);
\f
/* Return the rtx-label that corresponds to a LABEL_DECL,
creating it if necessary. */
-rtx
+rtx_insn *
label_rtx (tree label)
{
gcc_assert (TREE_CODE (label) == LABEL_DECL);
if (!DECL_RTL_SET_P (label))
{
- rtx r = gen_label_rtx ();
+ rtx_code_label *r = gen_label_rtx ();
SET_DECL_RTL (label, r);
if (FORCED_LABEL (label) || DECL_NONLOCAL (label))
LABEL_PRESERVE_P (r) = 1;
}
- return DECL_RTL (label);
+ return as_a <rtx_insn *> (DECL_RTL (label));
}
/* As above, but also put it on the forced-reference list of the
function that contains it. */
-rtx
+rtx_insn *
force_label_rtx (tree label)
{
- rtx ref = label_rtx (label);
+ rtx_insn *ref = label_rtx (label);
tree function = decl_function_context (label);
gcc_assert (function);
- forced_labels = gen_rtx_EXPR_LIST (VOIDmode, ref, forced_labels);
+ forced_labels = gen_rtx_INSN_LIST (VOIDmode, ref, forced_labels);
return ref;
}
+/* As label_rtx, but ensures (in check build), that returned value is
+ an existing label (i.e. rtx with code CODE_LABEL). */
+rtx_code_label *
+jump_target_rtx (tree label)
+{
+ return as_a <rtx_code_label *> (label_rtx (label));
+}
+
/* Add an unconditional jump to LABEL as the next sequential instruction. */
void
void
expand_label (tree label)
{
- rtx label_r = label_rtx (label);
+ rtx_code_label *label_r = jump_target_rtx (label);
do_pending_stack_adjust ();
emit_label (label_r);
{
expand_builtin_setjmp_receiver (NULL);
nonlocal_goto_handler_labels
- = gen_rtx_EXPR_LIST (VOIDmode, label_r,
+ = gen_rtx_INSN_LIST (VOIDmode, label_r,
nonlocal_goto_handler_labels);
}
if (FORCED_LABEL (label))
- forced_labels = gen_rtx_EXPR_LIST (VOIDmode, label_r, forced_labels);
+ forced_labels = gen_rtx_INSN_LIST (VOIDmode, label_r, forced_labels);
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
maybe_set_first_label_num (label_r);
}
break;
- case 'V': case TARGET_MEM_CONSTRAINT: case 'o':
- *allows_mem = true;
- break;
-
case '?': 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':
*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)
+ enum constraint_num cn = lookup_constraint (p);
+ if (reg_class_for_constraint (cn) != NO_REGS
+ || insn_extra_address_constraint (cn))
*allows_reg = true;
-#ifdef EXTRA_CONSTRAINT_STR
- else if (EXTRA_ADDRESS_CONSTRAINT (*p, p))
- *allows_reg = true;
- else if (EXTRA_MEMORY_CONSTRAINT (*p, p))
+ else if (insn_extra_memory_constraint (cn))
*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
+ insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
break;
}
}
break;
- case 'V': case TARGET_MEM_CONSTRAINT: case 'o':
- *allows_mem = true;
- break;
-
case '<': case '>':
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':
}
/* Fall through. */
- case 'p': case 'r':
- *allows_reg = true;
- break;
-
case 'g': case 'X':
*allows_reg = true;
*allows_mem = true;
error ("invalid punctuation %qc in constraint", constraint[j]);
return false;
}
- if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
- != NO_REGS)
+ enum constraint_num cn = lookup_constraint (constraint + j);
+ if (reg_class_for_constraint (cn) != NO_REGS
+ || insn_extra_address_constraint (cn))
*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))
+ else if (insn_extra_memory_constraint (cn))
*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
+ insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
break;
}
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. */
+/* 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. This is generally done in the front end while creating
+ the ASM_EXPR generic tree that eventually becomes the GIMPLE_ASM. */
tree
resolve_asm_operand_names (tree string, tree outputs, tree inputs, tree labels)
void
expand_naked_return (void)
{
- rtx end_label;
+ rtx_code_label *end_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
/* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. PROB
is the probability of jumping to LABEL. */
static void
-do_jump_if_equal (enum machine_mode mode, rtx op0, rtx op1, rtx label,
+do_jump_if_equal (machine_mode mode, rtx op0, rtx op1, rtx_code_label *label,
int unsignedp, int prob)
{
gcc_assert (prob <= REG_BR_PROB_BASE);
do_compare_rtx_and_jump (op0, op1, EQ, unsignedp, mode,
- NULL_RTX, NULL_RTX, label, prob);
+ NULL_RTX, NULL, label, prob);
}
\f
/* Do the insertion of a case label into case_list. The labels are
dump_case_nodes (FILE *f, struct case_node *root,
int indent_step, int indent_level)
{
- HOST_WIDE_INT low, high;
-
if (root == 0)
return;
indent_level++;
dump_case_nodes (f, root->left, indent_step, indent_level);
- low = tree_to_shwi (root->low);
- high = tree_to_shwi (root->high);
-
fputs (";; ", f);
- if (high == low)
- fprintf (f, "%*s" HOST_WIDE_INT_PRINT_DEC,
- indent_step * indent_level, "", low);
- else
- fprintf (f, "%*s" HOST_WIDE_INT_PRINT_DEC " ... " HOST_WIDE_INT_PRINT_DEC,
- indent_step * indent_level, "", low, high);
+ fprintf (f, "%*s", indent_step * indent_level, "");
+ print_dec (root->low, f, TYPE_SIGN (TREE_TYPE (root->low)));
+ if (!tree_int_cst_equal (root->low, root->high))
+ {
+ fprintf (f, " ... ");
+ print_dec (root->high, f, TYPE_SIGN (TREE_TYPE (root->high)));
+ }
fputs ("\n", f);
dump_case_nodes (f, root->right, indent_step, indent_level);
static void
emit_case_decision_tree (tree index_expr, tree index_type,
- struct case_node *case_list, rtx default_label,
- int default_prob)
+ case_node_ptr case_list, rtx_code_label *default_label,
+ int default_prob)
{
rtx index = expand_normal (index_expr);
&& ! have_insn_for (COMPARE, GET_MODE (index)))
{
int unsignedp = TYPE_UNSIGNED (index_type);
- enum machine_mode wider_mode;
+ 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))
struct case_node *n;
rtx *labelvec;
rtx fallback_label = label_rtx (case_list->code_label);
- rtx table_label = gen_label_rtx ();
+ rtx_code_label *table_label = gen_label_rtx ();
bool has_gaps = false;
edge default_edge = stmt_bb ? EDGE_SUCC (stmt_bb, 0) : NULL;
int default_prob = default_edge ? default_edge->probability : 0;
STMT. Record this information in the aux field of the edge. */
static inline void
-compute_cases_per_edge (gimple stmt)
+compute_cases_per_edge (gswitch *stmt)
{
basic_block bb = gimple_bb (stmt);
reset_out_edges_aux (bb);
Generate the code to test it and jump to the right place. */
void
-expand_case (gimple stmt)
+expand_case (gswitch *stmt)
{
tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
- rtx default_label = NULL_RTX;
+ rtx_code_label *default_label = NULL;
unsigned int count, uniq;
int i;
int ncases = gimple_switch_num_labels (stmt);
do_pending_stack_adjust ();
/* Find the default case target label. */
- default_label = label_rtx (CASE_LABEL (gimple_switch_default_label (stmt)));
+ default_label = jump_target_rtx
+ (CASE_LABEL (gimple_switch_default_label (stmt)));
edge default_edge = EDGE_SUCC (bb, 0);
int default_prob = default_edge->probability;
how to expand this switch(). */
uniq = 0;
count = 0;
- struct pointer_set_t *seen_labels = pointer_set_create ();
+ hash_set<tree> seen_labels;
compute_cases_per_edge (stmt);
for (i = ncases - 1; i >= 1; --i)
/* If we have not seen this label yet, then increase the
number of unique case node targets seen. */
- if (!pointer_set_insert (seen_labels, lab))
+ if (!seen_labels.add (lab))
uniq++;
/* The bounds on the case range, LOW and HIGH, have to be converted
case_edge->probability / (intptr_t)(case_edge->aux),
case_node_pool);
}
- pointer_set_destroy (seen_labels);
reset_out_edges_aux (bb);
/* cleanup_tree_cfg removes all SWITCH_EXPR with a single
type, so we should never get a zero here. */
gcc_assert (count > 0);
- rtx before_case = get_last_insn ();
+ rtx_insn *before_case = get_last_insn ();
/* Decide how to expand this switch.
The two options at this point are a dispatch table (casesi or
vec<tree> dispatch_table)
{
tree index_type = integer_type_node;
- enum machine_mode index_mode = TYPE_MODE (index_type);
+ machine_mode index_mode = TYPE_MODE (index_type);
int ncases = dispatch_table.length ();
do_pending_stack_adjust ();
- rtx before_case = get_last_insn ();
+ rtx_insn *before_case = get_last_insn ();
/* Expand as a decrement-chain if there are 5 or fewer dispatch
labels. This covers more than 98% of the cases in libjava,
for (int i = 0; i < ncases; i++)
{
tree elt = dispatch_table[i];
- rtx lab = label_rtx (CASE_LABEL (elt));
+ rtx_code_label *lab = jump_target_rtx (CASE_LABEL (elt));
do_jump_if_equal (index_mode, index, zero, lab, 0, -1);
force_expand_binop (index_mode, sub_optab,
index, CONST1_RTX (index_mode),
tree minval = build_int_cst (index_type, 0);
tree maxval = CASE_LOW (dispatch_table.last ());
tree range = maxval;
- rtx default_label = gen_label_rtx ();
+ rtx_code_label *default_label = gen_label_rtx ();
for (int i = ncases - 1; i >= 0; --i)
{
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,
+emit_case_nodes (rtx index, case_node_ptr node, rtx_code_label *default_label,
int default_prob, tree index_type)
{
/* If INDEX has an unsigned type, we must make unsigned branches. */
int unsignedp = TYPE_UNSIGNED (index_type);
int probability;
int prob = node->prob, subtree_prob = node->subtree_prob;
- enum machine_mode mode = GET_MODE (index);
- enum machine_mode imode = TYPE_MODE (index_type);
+ machine_mode mode = GET_MODE (index);
+ machine_mode imode = TYPE_MODE (index_type);
/* Handle indices detected as constant during RTL expansion. */
if (mode == VOIDmode)
convert_modes (mode, imode,
expand_normal (node->low),
unsignedp),
- label_rtx (node->code_label), unsignedp, probability);
+ jump_target_rtx (node->code_label),
+ unsignedp, probability);
/* Since this case is taken at this point, reduce its weight from
subtree_weight. */
subtree_prob -= prob;
LT, NULL_RTX, mode, unsignedp,
label_rtx (node->left->code_label),
probability);
- emit_case_nodes (index, node->right, default_label, default_prob, index_type);
+ emit_case_nodes (index, node->right, default_label, default_prob,
+ index_type);
}
/* If both children are single-valued cases with no
convert_modes (mode, imode,
expand_normal (node->right->low),
unsignedp),
- label_rtx (node->right->code_label),
+ jump_target_rtx (node->right->code_label),
unsignedp, probability);
/* See if the value matches what the left hand side
convert_modes (mode, imode,
expand_normal (node->left->low),
unsignedp),
- label_rtx (node->left->code_label),
+ jump_target_rtx (node->left->code_label),
unsignedp, probability);
}
tree test_label
= build_decl (curr_insn_location (),
- LABEL_DECL, NULL_TREE, NULL_TREE);
+ LABEL_DECL, NULL_TREE, void_type_node);
/* The default label could be reached either through the right
subtree or the left subtree. Divide the probability
(mode, imode,
expand_normal (node->right->low),
unsignedp),
- label_rtx (node->right->code_label), unsignedp, probability);
+ jump_target_rtx (node->right->code_label),
+ unsignedp, probability);
}
}
(mode, imode,
expand_normal (node->left->low),
unsignedp),
- label_rtx (node->left->code_label), unsignedp, probability);
+ jump_target_rtx (node->left->code_label),
+ unsignedp, probability);
}
}
}
Branch to a label where we will handle it later. */
test_label = build_decl (curr_insn_location (),
- LABEL_DECL, NULL_TREE, NULL_TREE);
+ LABEL_DECL, NULL_TREE, void_type_node);
probability = conditional_probability (
node->right->subtree_prob + default_prob/2,
subtree_prob + default_prob);
mode, 1, default_label, probability);
}
- emit_jump (label_rtx (node->code_label));
+ emit_jump (jump_target_rtx (node->code_label));
}
}
}