Index: gcc/gcc/stmt.c |
diff --git a/gcc/gcc/stmt.c b/gcc/gcc/stmt.c |
index 93fabcd273d0ecbd3a0bdf0ff4b1600d4a0f1dff..2778befd198507443ac5ec7f943ea632a3e793dc 100644 |
--- a/gcc/gcc/stmt.c |
+++ b/gcc/gcc/stmt.c |
@@ -1,7 +1,7 @@ |
/* Expands front end tree to back end RTL for GCC |
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, |
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
- Free Software Foundation, Inc. |
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
+ 2010 Free Software Foundation, Inc. |
This file is part of GCC. |
@@ -48,8 +48,10 @@ along with GCC; see the file COPYING3. If not see |
#include "predict.h" |
#include "optabs.h" |
#include "target.h" |
+#include "gimple.h" |
#include "regs.h" |
#include "alloc-pool.h" |
+#include "pretty-print.h" |
/* Functions and data structures for expanding case statements. */ |
@@ -108,8 +110,8 @@ 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 bool check_unique_operand_names (tree, tree, tree); |
+static char *resolve_operand_name_1 (char *, tree, tree, tree); |
static void expand_null_return_1 (void); |
static void expand_value_return (rtx); |
static int estimate_case_costs (case_node_ptr); |
@@ -600,8 +602,8 @@ tree_conflicts_with_clobbers_p (tree t, HARD_REG_SET *clobbered_regs) |
if (overlap) |
{ |
- error ("asm-specifier for variable %qs conflicts with asm clobber list", |
- IDENTIFIER_POINTER (DECL_NAME (overlap))); |
+ error ("asm-specifier for variable %qE conflicts with asm clobber list", |
+ DECL_NAME (overlap)); |
/* Reset registerness to stop multiple errors emitted for a single |
variable. */ |
@@ -631,12 +633,13 @@ tree_conflicts_with_clobbers_p (tree t, HARD_REG_SET *clobbered_regs) |
static void |
expand_asm_operands (tree string, tree outputs, tree inputs, |
- tree clobbers, int vol, location_t locus) |
+ tree clobbers, tree labels, int vol, location_t locus) |
{ |
- rtvec argvec, constraintvec; |
+ rtvec argvec, constraintvec, labelvec; |
rtx body; |
int ninputs = list_length (inputs); |
int noutputs = list_length (outputs); |
+ int nlabels = list_length (labels); |
int ninout; |
int nclobbers; |
HARD_REG_SET clobbered_regs; |
@@ -659,7 +662,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
if (! check_operand_nalternatives (outputs, inputs)) |
return; |
- string = resolve_asm_operand_names (string, outputs, inputs); |
+ string = resolve_asm_operand_names (string, outputs, inputs, labels); |
/* Collect constraints. */ |
i = 0; |
@@ -736,7 +739,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
|| (DECL_P (val) |
&& REG_P (DECL_RTL (val)) |
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))) |
- lang_hooks.mark_addressable (val); |
+ mark_addressable (val); |
if (is_inout) |
ninout++; |
@@ -765,7 +768,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
return; |
if (! allows_reg && allows_mem) |
- lang_hooks.mark_addressable (TREE_VALUE (tail)); |
+ mark_addressable (TREE_VALUE (tail)); |
} |
/* Second pass evaluates arguments. */ |
@@ -822,6 +825,8 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
{ |
op = assign_temp (type, 0, 0, 1); |
op = validize_mem (op); |
+ if (!MEM_P (op) && TREE_CODE (TREE_VALUE (tail)) == SSA_NAME) |
+ set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (TREE_VALUE (tail)), op); |
TREE_VALUE (tail) = make_tree (type, op); |
} |
output_rtx[i] = op; |
@@ -843,12 +848,13 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
argvec = rtvec_alloc (ninputs); |
constraintvec = rtvec_alloc (ninputs); |
+ labelvec = rtvec_alloc (nlabels); |
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); |
+ labelvec, locus); |
MEM_VOLATILE_P (body) = vol; |
@@ -931,7 +937,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
ASM_OPERANDS_INPUT (body, i) = op; |
ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i) |
- = gen_rtx_ASM_INPUT (TYPE_MODE (type), |
+ = gen_rtx_ASM_INPUT (TYPE_MODE (type), |
ggc_strdup (constraints[i + noutputs])); |
if (tree_conflicts_with_clobbers_p (val, &clobbered_regs)) |
@@ -957,6 +963,11 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
= gen_rtx_ASM_INPUT (inout_mode[i], ggc_strdup (buffer)); |
} |
+ /* Copy labels to the vector. */ |
+ for (i = 0, tail = labels; i < nlabels; ++i, tail = TREE_CHAIN (tail)) |
+ ASM_OPERANDS_LABEL (body, i) |
+ = gen_rtx_LABEL_REF (Pmode, label_rtx (TREE_VALUE (tail))); |
+ |
generating_concat_p = old_generating_concat_p; |
/* Now, for each output, construct an rtx |
@@ -964,18 +975,21 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
ARGVEC CONSTRAINTS OPNAMES)) |
If there is more than one, put them inside a PARALLEL. */ |
- if (noutputs == 1 && nclobbers == 0) |
+ if (nlabels > 0 && nclobbers == 0) |
{ |
- ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]); |
- emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body)); |
+ gcc_assert (noutputs == 0); |
+ emit_jump_insn (body); |
} |
- |
else if (noutputs == 0 && nclobbers == 0) |
{ |
/* No output operands: put in a raw ASM_OPERANDS rtx. */ |
emit_insn (body); |
} |
- |
+ else if (noutputs == 1 && nclobbers == 0) |
+ { |
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]); |
+ emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body)); |
+ } |
else |
{ |
rtx obody = body; |
@@ -996,7 +1010,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
(GET_MODE (output_rtx[i]), |
ggc_strdup (TREE_STRING_POINTER (string)), |
ggc_strdup (constraints[i]), |
- i, argvec, constraintvec, locus)); |
+ i, argvec, constraintvec, labelvec, locus)); |
MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol; |
} |
@@ -1060,7 +1074,10 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
= gen_rtx_CLOBBER (VOIDmode, clobbered_reg); |
} |
- emit_insn (body); |
+ if (nlabels > 0) |
+ emit_jump_insn (body); |
+ else |
+ emit_insn (body); |
} |
/* For any outputs that needed reloading into registers, spill them |
@@ -1074,20 +1091,66 @@ expand_asm_operands (tree string, tree outputs, tree inputs, |
} |
void |
-expand_asm_expr (tree exp) |
+expand_asm_stmt (gimple stmt) |
{ |
- int noutputs, i; |
- tree outputs, tail; |
+ int noutputs; |
+ tree outputs, tail, t; |
tree *o; |
+ size_t i, n; |
+ const char *s; |
+ tree str, out, in, cl, labels; |
+ location_t locus = gimple_location (stmt); |
+ |
+ /* Meh... convert the gimple asm operands into real tree lists. |
+ Eventually we should make all routines work on the vectors instead |
+ of relying on TREE_CHAIN. */ |
+ out = NULL_TREE; |
+ n = gimple_asm_noutputs (stmt); |
+ if (n > 0) |
+ { |
+ t = out = gimple_asm_output_op (stmt, 0); |
+ for (i = 1; i < n; i++) |
+ t = TREE_CHAIN (t) = gimple_asm_output_op (stmt, i); |
+ } |
- if (ASM_INPUT_P (exp)) |
+ in = NULL_TREE; |
+ n = gimple_asm_ninputs (stmt); |
+ if (n > 0) |
{ |
- expand_asm_loc (ASM_STRING (exp), ASM_VOLATILE_P (exp), input_location); |
+ t = in = gimple_asm_input_op (stmt, 0); |
+ for (i = 1; i < n; i++) |
+ t = TREE_CHAIN (t) = gimple_asm_input_op (stmt, i); |
+ } |
+ |
+ cl = NULL_TREE; |
+ n = gimple_asm_nclobbers (stmt); |
+ if (n > 0) |
+ { |
+ t = cl = gimple_asm_clobber_op (stmt, 0); |
+ for (i = 1; i < n; i++) |
+ t = TREE_CHAIN (t) = gimple_asm_clobber_op (stmt, i); |
+ } |
+ |
+ labels = NULL_TREE; |
+ n = gimple_asm_nlabels (stmt); |
+ if (n > 0) |
+ { |
+ t = labels = gimple_asm_label_op (stmt, 0); |
+ for (i = 1; i < n; i++) |
+ t = TREE_CHAIN (t) = gimple_asm_label_op (stmt, i); |
+ } |
+ |
+ s = gimple_asm_string (stmt); |
+ str = build_string (strlen (s), s); |
+ |
+ if (gimple_asm_input_p (stmt)) |
+ { |
+ expand_asm_loc (str, gimple_asm_volatile_p (stmt), locus); |
return; |
} |
- outputs = ASM_OUTPUTS (exp); |
- noutputs = list_length (outputs); |
+ outputs = out; |
+ noutputs = gimple_asm_noutputs (stmt); |
/* o[I] is the place that output number I should be written. */ |
o = (tree *) alloca (noutputs * sizeof (tree)); |
@@ -1097,9 +1160,8 @@ expand_asm_expr (tree exp) |
/* 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), |
- input_location); |
+ expand_asm_operands (str, outputs, in, cl, labels, |
+ gimple_asm_volatile_p (stmt), locus); |
/* Copy all the intermediate outputs into the specified outputs. */ |
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) |
@@ -1164,7 +1226,7 @@ check_operand_nalternatives (tree outputs, tree inputs) |
so all we need are pointer comparisons. */ |
static bool |
-check_unique_operand_names (tree outputs, tree inputs) |
+check_unique_operand_names (tree outputs, tree inputs, tree labels) |
{ |
tree i, j; |
@@ -1193,6 +1255,20 @@ check_unique_operand_names (tree outputs, tree inputs) |
goto failure; |
} |
+ for (i = labels; i ; i = TREE_CHAIN (i)) |
+ { |
+ tree i_name = 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 (j))) |
+ goto failure; |
+ for (j = inputs; j ; j = TREE_CHAIN (j)) |
+ if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j)))) |
+ goto failure; |
+ } |
+ |
return true; |
failure: |
@@ -1206,14 +1282,14 @@ check_unique_operand_names (tree outputs, tree inputs) |
STRING and in the constraints to those numbers. */ |
tree |
-resolve_asm_operand_names (tree string, tree outputs, tree inputs) |
+resolve_asm_operand_names (tree string, tree outputs, tree inputs, tree labels) |
{ |
char *buffer; |
char *p; |
const char *c; |
tree t; |
- check_unique_operand_names (outputs, inputs); |
+ check_unique_operand_names (outputs, inputs, labels); |
/* Substitute [<name>] in input constraint strings. There should be no |
named operands in output constraints. */ |
@@ -1224,7 +1300,7 @@ resolve_asm_operand_names (tree string, tree outputs, tree inputs) |
{ |
p = buffer = xstrdup (c); |
while ((p = strchr (p, '[')) != NULL) |
- p = resolve_operand_name_1 (p, outputs, inputs); |
+ p = resolve_operand_name_1 (p, outputs, inputs, NULL); |
TREE_VALUE (TREE_PURPOSE (t)) |
= build_string (strlen (buffer), buffer); |
free (buffer); |
@@ -1267,7 +1343,7 @@ resolve_asm_operand_names (tree string, tree outputs, tree inputs) |
continue; |
} |
- p = resolve_operand_name_1 (p, outputs, inputs); |
+ p = resolve_operand_name_1 (p, outputs, inputs, labels); |
} |
string = build_string (strlen (buffer), buffer); |
@@ -1283,53 +1359,49 @@ resolve_asm_operand_names (tree string, tree outputs, tree inputs) |
balance of the string after substitution. */ |
static char * |
-resolve_operand_name_1 (char *p, tree outputs, tree inputs) |
+resolve_operand_name_1 (char *p, tree outputs, tree inputs, tree labels) |
{ |
char *q; |
int op; |
tree t; |
- size_t len; |
/* Collect the operand name. */ |
- q = strchr (p, ']'); |
+ q = strchr (++p, ']'); |
if (!q) |
{ |
error ("missing close brace for named operand"); |
return strchr (p, '\0'); |
} |
- len = q - p - 1; |
+ *q = '\0'; |
/* 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; |
- } |
+ if (name && strcmp (TREE_STRING_POINTER (name), p) == 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; |
- } |
+ if (name && strcmp (TREE_STRING_POINTER (name), p) == 0) |
+ goto found; |
+ } |
+ for (t = labels; t ; t = TREE_CHAIN (t), op++) |
+ { |
+ tree name = TREE_PURPOSE (t); |
+ if (name && strcmp (TREE_STRING_POINTER (name), p) == 0) |
+ goto found; |
} |
- *q = '\0'; |
- error ("undefined named operand %qs", p + 1); |
+ error ("undefined named operand %qs", identifier_to_locale (p)); |
op = 0; |
- found: |
+ 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); |
+ sprintf (--p, "%d", op); |
p = strchr (p, '\0'); |
/* Verify the no extra buffer space assumption. */ |
@@ -1467,7 +1539,7 @@ warn_if_unused_value (const_tree exp, location_t locus) |
return 0; |
warn: |
- warning (OPT_Wunused_value, "%Hvalue computed is not used", &locus); |
+ warning_at (locus, OPT_Wunused_value, "value computed is not used"); |
return 1; |
} |
} |
@@ -1510,24 +1582,22 @@ expand_naked_return (void) |
static void |
expand_value_return (rtx val) |
{ |
- /* Copy the value to the return location |
- unless it's already there. */ |
+ /* Copy the value to the return location unless it's already there. */ |
- rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); |
+ tree decl = DECL_RESULT (current_function_decl); |
+ rtx return_reg = DECL_RTL (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); |
- } |
+ tree funtype = TREE_TYPE (current_function_decl); |
+ tree type = TREE_TYPE (decl); |
+ int unsignedp = TYPE_UNSIGNED (type); |
+ enum machine_mode old_mode = DECL_MODE (decl); |
+ enum machine_mode mode = promote_function_mode (type, old_mode, |
+ &unsignedp, funtype, 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 |
@@ -1730,13 +1800,17 @@ expand_return (tree retval) |
static void |
expand_nl_goto_receiver (void) |
{ |
+ rtx chain; |
+ |
/* Clobber the FP when we get here, so we have to make sure it's |
marked as used by this function. */ |
emit_use (hard_frame_pointer_rtx); |
/* Mark the static chain as clobbered here so life information |
doesn't get messed up for it. */ |
- emit_clobber (static_chain_rtx); |
+ chain = targetm.calls.static_chain (current_function_decl, true); |
+ if (chain && REG_P (chain)) |
+ emit_clobber (chain); |
#ifdef HAVE_nonlocal_goto |
if (! HAVE_nonlocal_goto) |
@@ -1847,9 +1921,7 @@ expand_decl (tree decl) |
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); |
+ enum machine_mode reg_mode = promote_decl_mode (decl, NULL); |
SET_DECL_RTL (decl, gen_reg_rtx (reg_mode)); |
@@ -2157,7 +2229,7 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval, |
Generate the code to test it and jump to the right place. */ |
void |
-expand_case (tree exp) |
+expand_case (gimple stmt) |
{ |
tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE; |
rtx default_label = 0; |
@@ -2170,9 +2242,7 @@ expand_case (tree exp) |
int i; |
rtx before_case, end, lab; |
- tree vec = SWITCH_LABELS (exp); |
- tree orig_type = TREE_TYPE (exp); |
- tree index_expr = SWITCH_COND (exp); |
+ tree index_expr = gimple_switch_index (stmt); |
tree index_type = TREE_TYPE (index_expr); |
int unsignedp = TYPE_UNSIGNED (index_type); |
@@ -2191,11 +2261,6 @@ expand_case (tree exp) |
sizeof (struct case_node), |
100); |
- /* The switch body is lowered in gimplify.c, we should never have |
- switches with a non-NULL SWITCH_BODY here. */ |
- 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. */ |
@@ -2203,24 +2268,24 @@ expand_case (tree exp) |
{ |
tree elt; |
bitmap label_bitmap; |
- int vl = TREE_VEC_LENGTH (vec); |
+ int stopi = 0; |
/* 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, if ever taken, is at the end of TREE_VEC. */ |
- elt = TREE_VEC_ELT (vec, vl - 1); |
+ /* The default case, if ever taken, is the first element. */ |
+ elt = gimple_switch_label (stmt, 0); |
if (!CASE_LOW (elt) && !CASE_HIGH (elt)) |
{ |
default_label_decl = CASE_LABEL (elt); |
- --vl; |
+ stopi = 1; |
} |
- for (i = vl - 1; i >= 0; --i) |
+ for (i = gimple_switch_num_labels (stmt) - 1; i >= stopi; --i) |
{ |
tree low, high; |
- elt = TREE_VEC_ELT (vec, i); |
+ elt = gimple_switch_label (stmt, i); |
low = CASE_LOW (elt); |
gcc_assert (low); |
@@ -2321,7 +2386,7 @@ expand_case (tree exp) |
If the switch-index is a constant, do it this way |
because we can optimize it. */ |
- else if (count < case_values_threshold () |
+ else if (count < targetm.case_values_threshold () |
|| compare_tree_int (range, |
(optimize_insn_for_size_p () ? 3 : 10) * count) > 0 |
/* RANGE may be signed, and really large ranges will show up |
@@ -2374,9 +2439,7 @@ expand_case (tree exp) |
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)); |
+ use_cost_table = estimate_case_costs (case_list); |
balance_case_nodes (&case_list, NULL); |
emit_case_nodes (index, case_list, default_label, index_type); |
if (default_label) |
@@ -2472,7 +2535,7 @@ 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); |
+ NULL_RTX, NULL_RTX, label, -1); |
} |
/* Not all case values are encountered equally. This function |
@@ -2904,7 +2967,9 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label, |
/* 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); |
+ tree test_label |
+ = build_decl (CURR_INSN_LOCATION, |
+ LABEL_DECL, NULL_TREE, NULL_TREE); |
/* See if the value is on the right. */ |
emit_cmp_and_jump_insns (index, |
@@ -3027,7 +3092,8 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label, |
/* 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); |
+ test_label = build_decl (CURR_INSN_LOCATION, |
+ LABEL_DECL, NULL_TREE, NULL_TREE); |
emit_cmp_and_jump_insns (index, |
convert_modes |
(mode, imode, |