summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/stmt.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-10-16 06:09:09 +0000
committerobrien <obrien@FreeBSD.org>1999-10-16 06:09:09 +0000
commitcae8fa8120c70195f34a2456f18c4c848a2d3e0c (patch)
treef7d3a3ab9c32694206552e767626366f016f2062 /contrib/gcc/stmt.c
parent84656b55b6e25e30322dc903a05de53706361d3d (diff)
downloadFreeBSD-src-cae8fa8120c70195f34a2456f18c4c848a2d3e0c.zip
FreeBSD-src-cae8fa8120c70195f34a2456f18c4c848a2d3e0c.tar.gz
Virgin import of the GCC 2.95.1 compilers
Diffstat (limited to 'contrib/gcc/stmt.c')
-rw-r--r--contrib/gcc/stmt.c1098
1 files changed, 698 insertions, 400 deletions
diff --git a/contrib/gcc/stmt.c b/contrib/gcc/stmt.c
index 8d11a75..018e190 100644
--- a/contrib/gcc/stmt.c
+++ b/contrib/gcc/stmt.c
@@ -1,5 +1,5 @@
/* Expands front end tree to back end RTL for GNU C-Compiler
- Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -88,45 +88,6 @@ static rtx last_block_end_note;
/* Number of binding contours started so far in this function. */
int block_start_count;
-
-/* Nonzero if function being compiled needs to
- return the address of where it has put a structure value. */
-
-extern int current_function_returns_pcc_struct;
-
-/* Label that will go on parm cleanup code, if any.
- Jumping to this label runs cleanup code for parameters, if
- such code must be run. Following this code is the logical return label. */
-
-extern rtx cleanup_label;
-
-/* Label that will go on function epilogue.
- Jumping to this label serves as a "return" instruction
- on machines which require execution of the epilogue on all returns. */
-
-extern rtx return_label;
-
-/* Offset to end of allocated area of stack frame.
- If stack grows down, this is the address of the last stack slot allocated.
- If stack grows up, this is the address for the next slot. */
-extern int frame_offset;
-
-/* Label to jump back to for tail recursion, or 0 if we have
- not yet needed one for this function. */
-extern rtx tail_recursion_label;
-
-/* Place after which to insert the tail_recursion_label if we need one. */
-extern rtx tail_recursion_reentry;
-
-/* Location at which to save the argument pointer if it will need to be
- referenced. There are two cases where this is done: if nonlocal gotos
- exist, or if vars whose is an offset from the argument pointer will be
- needed by inner routines. */
-
-extern rtx arg_pointer_save_area;
-
-/* Chain of all RTL_EXPRs that have insns in them. */
-extern tree rtl_expr_chain;
/* Functions and data structures for expanding case statements. */
@@ -306,7 +267,7 @@ struct nesting
/* Number of range exprs in case statement. */
int num_ranges;
/* Name of this kind of statement, for warnings. */
- char *printname;
+ const char *printname;
/* Used to save no_line_numbers till we see the first case label.
We set this to -1 when we see the first case label in this
case statement. */
@@ -425,8 +386,12 @@ struct label_chain
static int using_eh_for_cleanups_p = 0;
+static int n_occurrences PROTO((int, const char *));
static void expand_goto_internal PROTO((tree, rtx, rtx));
static int expand_fixup PROTO((tree, rtx, rtx));
+static rtx expand_nl_handler_label PROTO((rtx, rtx));
+static void expand_nl_goto_receiver PROTO((void));
+static void expand_nl_goto_receivers PROTO((struct nesting *));
static void fixup_gotos PROTO((struct nesting *, rtx, tree,
rtx, int));
static void expand_null_return_1 PROTO((rtx, int));
@@ -583,12 +548,14 @@ expand_computed_goto (exp)
emit_queue ();
/* Be sure the function is executable. */
- if (flag_check_memory_usage)
+ if (current_function_check_memory_usage)
emit_library_call (chkr_check_exec_libfunc, 1,
VOIDmode, 1, x, ptr_mode);
do_pending_stack_adjust ();
emit_indirect_jump (x);
+
+ current_function_has_computed_jump = 1;
}
/* Handle goto statements and the labels that they can go to. */
@@ -631,16 +598,18 @@ void
declare_nonlocal_label (label)
tree label;
{
+ rtx slot = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+
nonlocal_labels = tree_cons (NULL_TREE, label, nonlocal_labels);
LABEL_PRESERVE_P (label_rtx (label)) = 1;
- if (nonlocal_goto_handler_slot == 0)
+ if (nonlocal_goto_handler_slots == 0)
{
- nonlocal_goto_handler_slot
- = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
emit_stack_save (SAVE_NONLOCAL,
&nonlocal_goto_stack_level,
PREV_INSN (tail_recursion_reentry));
}
+ nonlocal_goto_handler_slots
+ = gen_rtx_EXPR_LIST (VOIDmode, slot, nonlocal_goto_handler_slots);
}
/* Generate RTL code for a `goto' statement with target label LABEL.
@@ -659,7 +628,15 @@ expand_goto (label)
{
struct function *p = find_function_data (context);
rtx label_ref = gen_rtx_LABEL_REF (Pmode, label_rtx (label));
- rtx temp;
+ rtx temp, handler_slot;
+ tree link;
+
+ /* Find the corresponding handler slot for this label. */
+ handler_slot = p->nonlocal_goto_handler_slots;
+ for (link = p->nonlocal_labels; TREE_VALUE (link) != label;
+ link = TREE_CHAIN (link))
+ handler_slot = XEXP (handler_slot, 1);
+ handler_slot = XEXP (handler_slot, 0);
p->has_nonlocal_label = 1;
current_function_has_nonlocal_goto = 1;
@@ -672,7 +649,7 @@ expand_goto (label)
#if HAVE_nonlocal_goto
if (HAVE_nonlocal_goto)
emit_insn (gen_nonlocal_goto (lookup_static_chain (label),
- copy_rtx (p->nonlocal_goto_handler_slot),
+ copy_rtx (handler_slot),
copy_rtx (p->nonlocal_goto_stack_level),
label_ref));
else
@@ -694,7 +671,7 @@ expand_goto (label)
/* Get addr of containing function's current nonlocal goto handler,
which will do any cleanups and then jump to the label. */
- addr = copy_rtx (p->nonlocal_goto_handler_slot);
+ addr = copy_rtx (handler_slot);
temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx,
hard_frame_pointer_rtx));
@@ -707,13 +684,10 @@ expand_goto (label)
emit_stack_restore (SAVE_NONLOCAL, addr, NULL_RTX);
- /* Put in the static chain register the nonlocal label address. */
- emit_move_insn (static_chain_rtx, label_ref);
/* USE of hard_frame_pointer_rtx added for consistency; not clear if
really needed. */
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
- emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx));
emit_indirect_jump (temp);
}
}
@@ -1102,8 +1076,18 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
f->stack_level = stack_level;
}
}
-
-
+
+/* Return the number of times character C occurs in string S. */
+static int
+n_occurrences (c, s)
+ int c;
+ const char *s;
+{
+ int n = 0;
+ while (*s)
+ n += (*s++ == c);
+ return n;
+}
/* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text,
@@ -1113,7 +1097,7 @@ void
expand_asm (body)
tree body;
{
- if (flag_check_memory_usage)
+ if (current_function_check_memory_usage)
{
error ("`asm' cannot be used with `-fcheck-memory-usage'");
return;
@@ -1160,6 +1144,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
/* Vector of RTX's of evaluated output operands. */
rtx *output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
int *inout_opnum = (int *) alloca (noutputs * sizeof (int));
+ rtx *real_output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
enum machine_mode *inout_mode
= (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
/* The insn we have emitted. */
@@ -1169,7 +1154,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (noutputs == 0)
vol = 1;
- if (flag_check_memory_usage)
+ if (current_function_check_memory_usage)
{
error ("`asm' cannot be used with `-fcheck-memory-usage'");
return;
@@ -1190,14 +1175,47 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
last_expr_type = 0;
+ /* Check that the number of alternatives is constant across all
+ operands. */
+ if (outputs || inputs)
+ {
+ tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
+ int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp));
+ tree next = inputs;
+
+ if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
+ {
+ error ("too many alternatives in `asm'");
+ return;
+ }
+
+ tmp = outputs;
+ while (tmp)
+ {
+ char *constraint = TREE_STRING_POINTER (TREE_PURPOSE (tmp));
+ if (n_occurrences (',', constraint) != nalternatives)
+ {
+ error ("operand constraints for `asm' differ in number of alternatives");
+ return;
+ }
+ if (TREE_CHAIN (tmp))
+ tmp = TREE_CHAIN (tmp);
+ else
+ tmp = next, next = 0;
+ }
+ }
+
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
{
tree val = TREE_VALUE (tail);
tree type = TREE_TYPE (val);
+ char *constraint;
+ char *p;
+ int c_len;
int j;
- int found_equal = 0;
- int found_plus = 0;
+ int is_inout = 0;
int allows_reg = 0;
+ int allows_mem = 0;
/* If there's an erroneous arg, emit no insn. */
if (TREE_TYPE (val) == error_mark_node)
@@ -1208,29 +1226,62 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
the worst that happens if we get it wrong is we issue an error
message. */
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
+ c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1;
+ constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+
+ /* 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. */
+ switch (c_len)
+ {
+ default:
+ if ((p = strchr (constraint, '=')) != NULL)
+ break;
+ if ((p = strchr (constraint, '+')) != NULL)
+ break;
+ case 0:
+ error ("output operand constraint lacks `='");
+ return;
+ }
+
+ if (p != constraint)
+ {
+ j = *p;
+ bcopy (constraint, constraint+1, p-constraint);
+ *constraint = j;
+
+ warning ("output constraint `%c' for operand %d is not at the beginning", j, i);
+ }
+
+ is_inout = constraint[0] == '+';
+ /* Replace '+' with '='. */
+ constraint[0] = '=';
+ /* Make sure we can specify the matching operand. */
+ if (is_inout && i > 9)
+ {
+ error ("output operand constraint %d contains `+'", i);
+ return;
+ }
+
+ for (j = 1; j < c_len; j++)
+ switch (constraint[j])
{
case '+':
- /* Make sure we can specify the matching operand. */
- if (i > 9)
+ case '=':
+ error ("operand constraint contains '+' or '=' at illegal position.");
+ return;
+
+ case '%':
+ if (i + 1 == ninputs + noutputs)
{
- error ("output operand constraint %d contains `+'", i);
+ error ("`%%' constraint used with last operand");
return;
}
-
- /* Replace '+' with '='. */
- TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] = '=';
- found_plus = 1;
break;
- case '=':
- found_equal = 1;
- break;
-
- case '?': case '!': case '*': case '%': case '&':
- case 'V': case 'm': case 'o': case '<': case '>':
- case 'E': case 'F': case 'G': case 'H': case 'X':
+ 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 ',':
@@ -1244,29 +1295,42 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
error ("matching constraint not valid in output operand");
break;
- case 'p': case 'g': case 'r':
+ case 'V': case 'm': case 'o':
+ allows_mem = 1;
+ break;
+
+ 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 = 1;
+ break;
+
+ case 'g': case 'X':
+ allows_reg = 1;
+ allows_mem = 1;
+ break;
+
+ case 'p': case 'r':
default:
allows_reg = 1;
break;
}
- if (! found_equal && ! found_plus)
- {
- error ("output operand constraint lacks `='");
- return;
- }
-
/* 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. */
- if (TREE_CODE (val) == INDIRECT_REF
+ real_output_rtx[i] = NULL_RTX;
+ if ((TREE_CODE (val) == INDIRECT_REF
+ && allows_mem)
|| (TREE_CODE_CLASS (TREE_CODE (val)) == 'd'
+ && (allows_mem || GET_CODE (DECL_RTL (val)) == REG)
&& ! (GET_CODE (DECL_RTL (val)) == REG
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
|| ! allows_reg
- || found_plus)
+ || is_inout)
{
if (! allows_reg)
mark_addressable (TREE_VALUE (tail));
@@ -1277,6 +1341,13 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
error ("output number %d not directly addressable", i);
+ if (! allows_mem && GET_CODE (output_rtx[i]) == MEM)
+ {
+ real_output_rtx[i] = protect_from_queue (output_rtx[i], 1);
+ output_rtx[i] = gen_reg_rtx (GET_MODE (output_rtx[i]));
+ if (is_inout)
+ emit_move_insn (output_rtx[i], real_output_rtx[i]);
+ }
}
else
{
@@ -1284,7 +1355,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
}
- if (found_plus)
+ if (is_inout)
{
inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
inout_opnum[ninout++] = i;
@@ -1316,13 +1387,18 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
{
int j;
- int allows_reg = 0;
+ int allows_reg = 0, allows_mem = 0;
+ char *constraint, *orig_constraint;
+ int c_len;
+ rtx op;
/* 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;
+
+ /* ??? Can this happen, and does the error message make any sense? */
if (TREE_PURPOSE (tail) == NULL_TREE)
{
error ("hard register `%s' listed as input operand to `asm'",
@@ -1330,18 +1406,38 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
return;
}
- /* Make sure constraint has neither `=' nor `+'. */
+ c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1;
+ constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+ orig_constraint = constraint;
+
+ /* Make sure constraint has neither `=', `+', nor '&'. */
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
+ for (j = 0; j < c_len; j++)
+ switch (constraint[j])
{
- case '+': case '=':
- error ("input operand constraint contains `%c'",
- TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]);
- return;
+ case '+': case '=': case '&':
+ if (constraint == orig_constraint)
+ {
+ error ("input operand constraint contains `%c'", constraint[j]);
+ return;
+ }
+ break;
- case '?': case '!': case '*': case '%': case '&':
- case 'V': case 'm': case 'o': case '<': case '>':
+ case '%':
+ if (constraint == orig_constraint
+ && i + 1 == ninputs - ninout)
+ {
+ error ("`%%' constraint used with last operand");
+ return;
+ }
+ break;
+
+ case 'V': case 'm': case 'o':
+ allows_mem = 1;
+ break;
+
+ case '<': case '>':
+ case '?': case '!': case '*':
case 'E': case 'F': case 'G': case 'H': case 'X':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L': case 'M':
@@ -1358,56 +1454,81 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
operands to memory. */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]
- >= '0' + noutputs)
+ if (constraint[j] >= '0' + noutputs)
{
error
("matching constraint references invalid operand number");
return;
}
+ /* Try and find the real constraint for this dup. */
+ if ((j == 0 && c_len == 1)
+ || (j == 1 && c_len == 2 && constraint[0] == '%'))
+ {
+ tree o = outputs;
+ for (j = constraint[j] - '0'; j > 0; --j)
+ o = TREE_CHAIN (o);
+
+ c_len = TREE_STRING_LENGTH (TREE_PURPOSE (o)) - 1;
+ constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
+ j = 0;
+ break;
+ }
+
/* ... fall through ... */
- case 'p': case 'g': case 'r':
+ case 'p': case 'r':
default:
allows_reg = 1;
break;
+
+ case 'g':
+ allows_reg = 1;
+ allows_mem = 1;
+ break;
}
- if (! allows_reg)
+ if (! allows_reg && allows_mem)
mark_addressable (TREE_VALUE (tail));
- XVECEXP (body, 3, i) /* argvec */
- = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
- if (CONSTANT_P (XVECEXP (body, 3, i))
- && ! general_operand (XVECEXP (body, 3, i),
- TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)))))
+ op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
+
+ if (asm_operand_ok (op, constraint) <= 0)
{
if (allows_reg)
- XVECEXP (body, 3, i)
- = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
- XVECEXP (body, 3, i));
+ op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
+ else if (!allows_mem)
+ warning ("asm operand %d probably doesn't match constraints", i);
+ else if (CONSTANT_P (op))
+ op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
+ op);
+ else if (GET_CODE (op) == REG
+ || GET_CODE (op) == SUBREG
+ || GET_CODE (op) == CONCAT)
+ {
+ tree type = TREE_TYPE (TREE_VALUE (tail));
+ rtx memloc = assign_temp (type, 1, 1, 1);
+
+ emit_move_insn (memloc, op);
+ op = memloc;
+ }
+ else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
+ /* We won't recognize volatile memory as available a
+ memory_operand at this point. Ignore it. */
+ ;
+ else if (queued_subexp_p (op))
+ ;
else
- XVECEXP (body, 3, i)
- = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
- XVECEXP (body, 3, i));
+ /* ??? Leave this only until we have experience with what
+ happens in combine and elsewhere when constraints are
+ not satisfied. */
+ warning ("asm operand %d probably doesn't match constraints", i);
}
+ XVECEXP (body, 3, i) = op;
- if (! allows_reg
- && (GET_CODE (XVECEXP (body, 3, i)) == REG
- || GET_CODE (XVECEXP (body, 3, i)) == SUBREG
- || GET_CODE (XVECEXP (body, 3, i)) == CONCAT))
- {
- tree type = TREE_TYPE (TREE_VALUE (tail));
- rtx memloc = assign_temp (type, 1, 1, 1);
-
- emit_move_insn (memloc, XVECEXP (body, 3, i));
- XVECEXP (body, 3, i) = memloc;
- }
-
XVECEXP (body, 4, i) /* constraints */
= gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
- TREE_STRING_POINTER (TREE_PURPOSE (tail)));
+ orig_constraint);
i++;
}
@@ -1509,6 +1630,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
insn = 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 ();
}
@@ -1539,13 +1666,10 @@ expand_expr_stmt (exp)
exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
last_expr_type = TREE_TYPE (exp);
- if (flag_syntax_only && ! expr_stmts_for_value)
- last_expr_value = 0;
- else
- last_expr_value = expand_expr (exp,
- (expr_stmts_for_value
- ? NULL_RTX : const0_rtx),
- VOIDmode, 0);
+ last_expr_value = expand_expr (exp,
+ (expr_stmts_for_value
+ ? NULL_RTX : const0_rtx),
+ VOIDmode, 0);
/* If all we do is reference a volatile value in memory,
copy it to a register to be sure it is actually touched. */
@@ -1561,12 +1685,12 @@ expand_expr_stmt (exp)
rtx lab = gen_label_rtx ();
/* Compare the value with itself to reference it. */
- emit_cmp_insn (last_expr_value, last_expr_value, EQ,
- expand_expr (TYPE_SIZE (last_expr_type),
- NULL_RTX, VOIDmode, 0),
- BLKmode, 0,
- TYPE_ALIGN (last_expr_type) / BITS_PER_UNIT);
- emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (lab));
+ emit_cmp_and_jump_insns (last_expr_value, last_expr_value, EQ,
+ expand_expr (TYPE_SIZE (last_expr_type),
+ NULL_RTX, VOIDmode, 0),
+ BLKmode, 0,
+ TYPE_ALIGN (last_expr_type) / BITS_PER_UNIT,
+ lab);
emit_label (lab);
}
}
@@ -1917,13 +2041,9 @@ expand_loop_continue_here ()
void
expand_end_loop ()
{
- register rtx insn;
- register rtx start_label;
- rtx last_test_insn = 0;
- int num_insns = 0;
-
- insn = get_last_insn ();
- start_label = loop_stack->data.loop.start_label;
+ rtx start_label = loop_stack->data.loop.start_label;
+ rtx insn = get_last_insn ();
+ int needs_end_jump = 1;
/* Mark the continue-point at the top of the loop if none elsewhere. */
if (start_label == loop_stack->data.loop.continue_label)
@@ -1931,9 +2051,77 @@ expand_end_loop ()
do_pending_stack_adjust ();
- /* If optimizing, perhaps reorder the loop. If the loop starts with
- a loop exit, roll that to the end where it will optimize together
- with the jump back.
+ /* If optimizing, perhaps reorder the loop.
+ First, try to use a condjump near the end.
+ expand_exit_loop_if_false ends loops with unconditional jumps,
+ like this:
+
+ if (test) goto label;
+ optional: cleanup
+ goto loop_stack->data.loop.end_label
+ barrier
+ label:
+
+ If we find such a pattern, we can end the loop earlier. */
+
+ if (optimize
+ && GET_CODE (insn) == CODE_LABEL
+ && LABEL_NAME (insn) == NULL
+ && GET_CODE (PREV_INSN (insn)) == BARRIER)
+ {
+ rtx label = insn;
+ rtx jump = PREV_INSN (PREV_INSN (label));
+
+ if (GET_CODE (jump) == JUMP_INSN
+ && GET_CODE (PATTERN (jump)) == SET
+ && SET_DEST (PATTERN (jump)) == pc_rtx
+ && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
+ && (XEXP (SET_SRC (PATTERN (jump)), 0)
+ == loop_stack->data.loop.end_label))
+ {
+ rtx prev;
+
+ /* The test might be complex and reference LABEL multiple times,
+ like the loop in loop_iterations to set vtop. To handle this,
+ we move LABEL. */
+ insn = PREV_INSN (label);
+ reorder_insns (label, label, start_label);
+
+ for (prev = PREV_INSN (jump); ; prev = PREV_INSN (prev))
+ {
+ /* We ignore line number notes, but if we see any other note,
+ in particular NOTE_INSN_BLOCK_*, NOTE_INSN_EH_REGION_*,
+ NOTE_INSN_LOOP_*, we disable this optimization. */
+ if (GET_CODE (prev) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (prev) < 0)
+ break;
+ continue;
+ }
+ if (GET_CODE (prev) == CODE_LABEL)
+ break;
+ if (GET_CODE (prev) == JUMP_INSN)
+ {
+ if (GET_CODE (PATTERN (prev)) == SET
+ && SET_DEST (PATTERN (prev)) == pc_rtx
+ && GET_CODE (SET_SRC (PATTERN (prev))) == IF_THEN_ELSE
+ && (GET_CODE (XEXP (SET_SRC (PATTERN (prev)), 1))
+ == LABEL_REF)
+ && XEXP (XEXP (SET_SRC (PATTERN (prev)), 1), 0) == label)
+ {
+ XEXP (XEXP (SET_SRC (PATTERN (prev)), 1), 0)
+ = start_label;
+ emit_note_after (NOTE_INSN_LOOP_END, prev);
+ needs_end_jump = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /* If the loop starts with a loop exit, roll that to the end where
+ it will optimize together with the jump back.
We look for the conditional branch to the exit, except that once
we find such a branch, we don't look past 30 instructions.
@@ -1944,7 +2132,7 @@ expand_end_loop ()
if (test) goto end_label;
body;
goto start_label;
- end_label;
+ end_label:
transform it to look like:
@@ -1954,11 +2142,13 @@ expand_end_loop ()
start_label:
if (test) goto end_label;
goto newstart_label;
- end_label;
+ end_label:
Here, the `test' may actually consist of some reasonably complex
code, terminating in a test. */
+
if (optimize
+ && needs_end_jump
&&
! (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == SET
@@ -1966,6 +2156,8 @@ expand_end_loop ()
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
{
int eh_regions = 0;
+ int num_insns = 0;
+ rtx last_test_insn = NULL_RTX;
/* Scan insns from the top of the loop looking for a qualified
conditional exit. */
@@ -2001,6 +2193,10 @@ expand_end_loop ()
abort ();
}
+ /* We must not walk into a nested loop. */
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ break;
+
/* We already know this INSN is a NOTE, so there's no
point in looking at it to see if it's a JUMP. */
continue;
@@ -2042,31 +2238,46 @@ expand_end_loop ()
So we don't look for tests within an EH region. */
continue;
- if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == pc_rtx
- && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
- && ((GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == LABEL_REF
- && ((XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0)
- == loop_stack->data.loop.end_label)
- || (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0)
- == loop_stack->data.loop.alt_end_label)))
- || (GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 2)) == LABEL_REF
- && ((XEXP (XEXP (SET_SRC (PATTERN (insn)), 2), 0)
- == loop_stack->data.loop.end_label)
- || (XEXP (XEXP (SET_SRC (PATTERN (insn)), 2), 0)
- == loop_stack->data.loop.alt_end_label)))))
- last_test_insn = insn;
-
- if (last_test_insn == 0 && GET_CODE (insn) == JUMP_INSN
+ if (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == pc_rtx
- && GET_CODE (SET_SRC (PATTERN (insn))) == LABEL_REF
- && ((XEXP (SET_SRC (PATTERN (insn)), 0)
- == loop_stack->data.loop.end_label)
- || (XEXP (SET_SRC (PATTERN (insn)), 0)
- == loop_stack->data.loop.alt_end_label)))
- /* Include BARRIER. */
- last_test_insn = NEXT_INSN (insn);
+ && SET_DEST (PATTERN (insn)) == pc_rtx)
+ {
+ /* This is indeed a jump. */
+ rtx dest1 = NULL_RTX;
+ rtx dest2 = NULL_RTX;
+ rtx potential_last_test;
+ if (GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
+ {
+ /* A conditional jump. */
+ dest1 = XEXP (SET_SRC (PATTERN (insn)), 1);
+ dest2 = XEXP (SET_SRC (PATTERN (insn)), 2);
+ potential_last_test = insn;
+ }
+ else
+ {
+ /* An unconditional jump. */
+ dest1 = SET_SRC (PATTERN (insn));
+ /* Include the BARRIER after the JUMP. */
+ potential_last_test = NEXT_INSN (insn);
+ }
+
+ do {
+ if (dest1 && GET_CODE (dest1) == LABEL_REF
+ && ((XEXP (dest1, 0)
+ == loop_stack->data.loop.alt_end_label)
+ || (XEXP (dest1, 0)
+ == loop_stack->data.loop.end_label)))
+ {
+ last_test_insn = potential_last_test;
+ break;
+ }
+
+ /* If this was a conditional jump, there may be
+ another label at which we should look. */
+ dest1 = dest2;
+ dest2 = NULL_RTX;
+ } while (dest1);
+ }
}
if (last_test_insn != 0 && last_test_insn != get_last_insn ())
@@ -2125,8 +2336,11 @@ expand_end_loop ()
}
}
- emit_jump (start_label);
- emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
+ if (needs_end_jump)
+ {
+ emit_jump (start_label);
+ emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
+ }
emit_label (loop_stack->data.loop.end_label);
POPSTACK (loop_stack);
@@ -2202,6 +2416,14 @@ expand_exit_loop_if_false (whichloop, cond)
return 1;
}
+/* Return nonzero if the loop nest is empty. Else return zero. */
+
+int
+stmt_loop_nest_empty ()
+{
+ return (loop_stack == NULL);
+}
+
/* Return non-zero if we should preserve sub-expressions as separate
pseudos. We never do so if we aren't optimizing. We always do so
if -fexpensive-optimizations.
@@ -2442,6 +2664,7 @@ expand_return (retval)
tree expr;
do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
+ start_cleanup_deferral ();
expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
DECL_RESULT (current_function_decl),
TREE_OPERAND (retval_rhs, 1));
@@ -2454,35 +2677,14 @@ expand_return (retval)
TREE_OPERAND (retval_rhs, 2));
TREE_SIDE_EFFECTS (expr) = 1;
expand_return (expr);
+ end_cleanup_deferral ();
return;
}
- /* For tail-recursive call to current function,
- just jump back to the beginning.
- It's unsafe if any auto variable in this function
- has its address taken; for simplicity,
- require stack frame to be empty. */
- if (optimize && retval_rhs != 0
- && frame_offset == 0
- && TREE_CODE (retval_rhs) == CALL_EXPR
- && TREE_CODE (TREE_OPERAND (retval_rhs, 0)) == ADDR_EXPR
- && TREE_OPERAND (TREE_OPERAND (retval_rhs, 0), 0) == current_function_decl
- /* Finish checking validity, and if valid emit code
- to set the argument variables for the new call. */
- && tail_recursion_args (TREE_OPERAND (retval_rhs, 1),
- DECL_ARGUMENTS (current_function_decl)))
- {
- if (tail_recursion_label == 0)
- {
- tail_recursion_label = gen_label_rtx ();
- emit_label_after (tail_recursion_label,
- tail_recursion_reentry);
- }
- emit_queue ();
- expand_goto_internal (NULL_TREE, tail_recursion_label, last_insn);
- emit_barrier ();
- return;
- }
+ /* Attempt to optimize the call if it is tail recursive. */
+ if (optimize_tail_recursion (retval_rhs, last_insn))
+ return;
+
#ifdef HAVE_return
/* This optimization is safe if there are local cleanups
because expand_null_return takes care of them.
@@ -2564,7 +2766,8 @@ expand_return (retval)
int big_endian_correction = 0;
int bytes = int_size_in_bytes (TREE_TYPE (retval_rhs));
int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
- int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)),BITS_PER_WORD);
+ int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)),
+ (unsigned int)BITS_PER_WORD);
rtx *result_pseudos = (rtx *) alloca (sizeof (rtx) * n_regs);
rtx result_reg, src = NULL_RTX, dst = NULL_RTX;
rtx result_val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
@@ -2686,6 +2889,49 @@ drop_through_at_end_p ()
return insn && GET_CODE (insn) != BARRIER;
}
+/* Test CALL_EXPR to determine if it is a potential tail recursion call
+ and emit code to optimize the tail recursion. LAST_INSN indicates where
+ to place the jump to the tail recursion label. Return TRUE if the
+ call was optimized into a goto.
+
+ This is only used by expand_return, but expand_call is expected to
+ use it soon. */
+
+int
+optimize_tail_recursion (call_expr, last_insn)
+ tree call_expr;
+ rtx last_insn;
+{
+ /* For tail-recursive call to current function,
+ just jump back to the beginning.
+ It's unsafe if any auto variable in this function
+ has its address taken; for simplicity,
+ require stack frame to be empty. */
+ if (optimize && call_expr != 0
+ && frame_offset == 0
+ && TREE_CODE (call_expr) == CALL_EXPR
+ && TREE_CODE (TREE_OPERAND (call_expr, 0)) == ADDR_EXPR
+ && TREE_OPERAND (TREE_OPERAND (call_expr, 0), 0) == current_function_decl
+ /* Finish checking validity, and if valid emit code
+ to set the argument variables for the new call. */
+ && tail_recursion_args (TREE_OPERAND (call_expr, 1),
+ DECL_ARGUMENTS (current_function_decl)))
+ {
+ if (tail_recursion_label == 0)
+ {
+ tail_recursion_label = gen_label_rtx ();
+ emit_label_after (tail_recursion_label,
+ tail_recursion_reentry);
+ }
+ emit_queue ();
+ expand_goto_internal (NULL_TREE, tail_recursion_label, last_insn);
+ emit_barrier ();
+ return 1;
+ }
+
+ return 0;
+}
+
/* Emit code to alter this function's formal parms for a tail-recursive call.
ACTUALS is a list of actual parameter expressions (chain of TREE_LISTs).
FORMALS is the chain of decls of formals.
@@ -2900,9 +3146,177 @@ remember_end_note (block)
last_block_end_note = NULL_RTX;
}
+/* Emit a handler label for a nonlocal goto handler.
+ Also emit code to store the handler label in SLOT before BEFORE_INSN. */
+
+static rtx
+expand_nl_handler_label (slot, before_insn)
+ rtx slot, before_insn;
+{
+ rtx insns;
+ rtx handler_label = gen_label_rtx ();
+
+ /* Don't let jump_optimize delete the handler. */
+ LABEL_PRESERVE_P (handler_label) = 1;
+
+ start_sequence ();
+ emit_move_insn (slot, gen_rtx_LABEL_REF (Pmode, handler_label));
+ insns = get_insns ();
+ end_sequence ();
+ emit_insns_before (insns, before_insn);
+
+ emit_label (handler_label);
+
+ return handler_label;
+}
+
+/* Emit code to restore vital registers at the beginning of a nonlocal goto
+ handler. */
+static void
+expand_nl_goto_receiver ()
+{
+#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 struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+ size_t i;
+
+ for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+ if (elim_regs[i].from == ARG_POINTER_REGNUM
+ && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+ break;
+
+ if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+ {
+ /* Now restore our arg pointer from the address at which it
+ was saved in our stack frame.
+ If there hasn't be space allocated for it yet, make
+ some now. */
+ if (arg_pointer_save_area == 0)
+ arg_pointer_save_area
+ = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+ emit_move_insn (virtual_incoming_args_rtx,
+ /* We need a pseudo here, or else
+ instantiate_virtual_regs_1 complains. */
+ copy_to_reg (arg_pointer_save_area));
+ }
+ }
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+}
+
+/* Make handlers for nonlocal gotos taking place in the function calls in
+ block THISBLOCK. */
+
+static void
+expand_nl_goto_receivers (thisblock)
+ struct nesting *thisblock;
+{
+ tree link;
+ rtx afterward = gen_label_rtx ();
+ rtx insns, slot;
+ rtx label_list;
+ int any_invalid;
+
+ /* Record the handler address in the stack slot for that purpose,
+ during this block, saving and restoring the outer value. */
+ if (thisblock->next != 0)
+ for (slot = nonlocal_goto_handler_slots; slot; slot = XEXP (slot, 1))
+ {
+ rtx save_receiver = gen_reg_rtx (Pmode);
+ emit_move_insn (XEXP (slot, 0), save_receiver);
+
+ start_sequence ();
+ emit_move_insn (save_receiver, XEXP (slot, 0));
+ insns = get_insns ();
+ end_sequence ();
+ emit_insns_before (insns, thisblock->data.block.first_insn);
+ }
+
+ /* Jump around the handlers; they run only when specially invoked. */
+ emit_jump (afterward);
+
+ /* Make a separate handler for each label. */
+ link = nonlocal_labels;
+ slot = nonlocal_goto_handler_slots;
+ label_list = NULL_RTX;
+ for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1))
+ /* Skip any labels we shouldn't be able to jump to from here,
+ we generate one special handler for all of them below which just calls
+ abort. */
+ if (! DECL_TOO_LATE (TREE_VALUE (link)))
+ {
+ rtx lab;
+ lab = expand_nl_handler_label (XEXP (slot, 0),
+ thisblock->data.block.first_insn);
+ label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list);
+
+ expand_nl_goto_receiver ();
+
+ /* Jump to the "real" nonlocal label. */
+ expand_goto (TREE_VALUE (link));
+ }
+
+ /* A second pass over all nonlocal labels; this time we handle those
+ we should not be able to jump to at this point. */
+ link = nonlocal_labels;
+ slot = nonlocal_goto_handler_slots;
+ any_invalid = 0;
+ for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1))
+ if (DECL_TOO_LATE (TREE_VALUE (link)))
+ {
+ rtx lab;
+ lab = expand_nl_handler_label (XEXP (slot, 0),
+ thisblock->data.block.first_insn);
+ label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list);
+ any_invalid = 1;
+ }
+
+ if (any_invalid)
+ {
+ expand_nl_goto_receiver ();
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
+ VOIDmode, 0);
+ emit_barrier ();
+ }
+
+ nonlocal_goto_handler_labels = label_list;
+ emit_label (afterward);
+}
+
/* Generate RTL code to terminate a binding contour.
- VARS is the chain of VAR_DECL nodes
- for the variables bound in this contour.
+
+ VARS is the chain of VAR_DECL nodes for the variables bound in this
+ contour. There may actually be other nodes in this chain, but any
+ nodes other than VAR_DECLS are ignored.
+
MARK_ENDS is nonzero if we should put a note at the beginning
and end of this binding contour.
@@ -2939,7 +3353,8 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
if (warn_unused)
for (decl = vars; decl; decl = TREE_CHAIN (decl))
- if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
+ if (TREE_CODE (decl) == VAR_DECL
+ && ! TREE_USED (decl)
&& ! DECL_IN_SYSTEM_HEADER (decl)
&& DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
warning_with_decl (decl, "unused variable `%s'");
@@ -2950,7 +3365,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
emit_label (thisblock->exit_label);
}
- /* If necessary, make a handler for nonlocal gotos taking
+ /* If necessary, make handlers for nonlocal gotos taking
place in the function calls in this block. */
if (function_call_count != thisblock->data.block.function_call_count
&& nonlocal_labels
@@ -2961,119 +3376,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
special to do when you jump out of it. */
: (thisblock->data.block.cleanups != 0
|| thisblock->data.block.stack_level != 0)))
- {
- tree link;
- rtx afterward = gen_label_rtx ();
- rtx handler_label = gen_label_rtx ();
- rtx save_receiver = gen_reg_rtx (Pmode);
- rtx insns;
-
- /* Don't let jump_optimize delete the handler. */
- LABEL_PRESERVE_P (handler_label) = 1;
-
- /* Record the handler address in the stack slot for that purpose,
- during this block, saving and restoring the outer value. */
- if (thisblock->next != 0)
- {
- emit_move_insn (nonlocal_goto_handler_slot, save_receiver);
-
- start_sequence ();
- emit_move_insn (save_receiver, nonlocal_goto_handler_slot);
- insns = get_insns ();
- end_sequence ();
- emit_insns_before (insns, thisblock->data.block.first_insn);
- }
-
- start_sequence ();
- emit_move_insn (nonlocal_goto_handler_slot,
- gen_rtx_LABEL_REF (Pmode, handler_label));
- insns = get_insns ();
- end_sequence ();
- emit_insns_before (insns, thisblock->data.block.first_insn);
-
- /* Jump around the handler; it runs only when specially invoked. */
- emit_jump (afterward);
- emit_label (handler_label);
-
-#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 struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
- size_t i;
-
- for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
- if (elim_regs[i].from == ARG_POINTER_REGNUM
- && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
- break;
-
- if (i == sizeof elim_regs / sizeof elim_regs [0])
-#endif
- {
- /* Now restore our arg pointer from the address at which it
- was saved in our stack frame.
- If there hasn't be space allocated for it yet, make
- some now. */
- if (arg_pointer_save_area == 0)
- arg_pointer_save_area
- = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
- emit_move_insn (virtual_incoming_args_rtx,
- /* We need a pseudo here, or else
- instantiate_virtual_regs_1 complains. */
- copy_to_reg (arg_pointer_save_area));
- }
- }
-#endif
-
-#ifdef HAVE_nonlocal_goto_receiver
- if (HAVE_nonlocal_goto_receiver)
- emit_insn (gen_nonlocal_goto_receiver ());
-#endif
-
- /* The handler expects the desired label address in the static chain
- register. It tests the address and does an appropriate jump
- to whatever label is desired. */
- for (link = nonlocal_labels; link; link = TREE_CHAIN (link))
- /* Skip any labels we shouldn't be able to jump to from here. */
- if (! DECL_TOO_LATE (TREE_VALUE (link)))
- {
- rtx not_this = gen_label_rtx ();
- rtx this = gen_label_rtx ();
- do_jump_if_equal (static_chain_rtx,
- gen_rtx_LABEL_REF (Pmode, DECL_RTL (TREE_VALUE (link))),
- this, 0);
- emit_jump (not_this);
- emit_label (this);
- expand_goto (TREE_VALUE (link));
- emit_label (not_this);
- }
- /* If label is not recognized, abort. */
- emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
- VOIDmode, 0);
- emit_barrier ();
- emit_label (afterward);
- }
+ expand_nl_goto_receivers (thisblock);
/* Don't allow jumping into a block that has a stack level.
Cleanups are allowed, though. */
@@ -3127,7 +3430,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
{
emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
thisblock->data.block.stack_level, NULL_RTX);
- if (nonlocal_goto_handler_slot != 0)
+ if (nonlocal_goto_handler_slots != 0)
emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level,
NULL_RTX);
}
@@ -3157,11 +3460,8 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
if (obey_regdecls)
for (decl = vars; decl; decl = TREE_CHAIN (decl))
- {
- rtx rtl = DECL_RTL (decl);
- if (TREE_CODE (decl) == VAR_DECL && rtl != 0)
- use_variable (rtl);
- }
+ if (TREE_CODE (decl) == VAR_DECL && DECL_RTL (decl))
+ use_variable (DECL_RTL (decl));
/* Restore the temporary level of TARGET_EXPRs. */
target_temp_slot_level = thisblock->data.block.target_temp_slot_level;
@@ -3174,8 +3474,6 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
/* Pop the stack slot nesting and free any slots at this level. */
pop_temp_slots ();
}
-
-
/* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.) */
@@ -3214,7 +3512,7 @@ expand_decl (decl)
/* An initializer is going to decide the size of this array.
Until we know the size, represent its address with a reg. */
DECL_RTL (decl) = gen_rtx_MEM (BLKmode, gen_reg_rtx (Pmode));
- MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (type);
+ MEM_SET_IN_STRUCT_P (DECL_RTL (decl), AGGREGATE_TYPE_P (type));
}
else if (DECL_MODE (decl) != BLKmode
/* If -ffloat-store, don't put explicit float vars
@@ -3225,7 +3523,7 @@ expand_decl (decl)
&& ! TREE_ADDRESSABLE (decl)
&& (DECL_REGISTER (decl) || ! obey_regdecls)
/* if -fcheck-memory-usage, check all variables. */
- && ! flag_check_memory_usage)
+ && ! current_function_check_memory_usage)
{
/* Automatic variable that can go in a register. */
int unsignedp = TREE_UNSIGNED (type);
@@ -3263,13 +3561,9 @@ expand_decl (decl)
oldaddr = XEXP (DECL_RTL (decl), 0);
}
- DECL_RTL (decl)
- = assign_stack_temp (DECL_MODE (decl),
- ((TREE_INT_CST_LOW (DECL_SIZE (decl))
- + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT),
- 1);
- MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
+ DECL_RTL (decl) = assign_temp (TREE_TYPE (decl), 1, 1, 1);
+ MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
+ AGGREGATE_TYPE_P (TREE_TYPE (decl)));
/* Set alignment we actually gave this decl. */
DECL_ALIGN (decl) = (DECL_MODE (decl) == BLKmode ? BIGGEST_ALIGNMENT
@@ -3284,7 +3578,8 @@ expand_decl (decl)
/* If this is a memory ref that contains aggregate components,
mark it as such for cse and loop optimize. */
- MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
+ MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
+ AGGREGATE_TYPE_P (TREE_TYPE (decl)));
#if 0
/* If this is in memory because of -ffloat-store,
set the volatile bit, to prevent optimizations from
@@ -3330,7 +3625,8 @@ expand_decl (decl)
/* If this is a memory ref that contains aggregate components,
mark it as such for cse and loop optimize. */
- MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
+ MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
+ AGGREGATE_TYPE_P (TREE_TYPE (decl)));
/* Indicate the alignment we actually gave this variable. */
#ifdef STACK_BOUNDARY
@@ -3663,7 +3959,7 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
else
{
DECL_RTL (decl_elt) = gen_rtx_MEM (mode, copy_rtx (XEXP (x, 0)));
- MEM_IN_STRUCT_P (DECL_RTL (decl_elt)) = MEM_IN_STRUCT_P (x);
+ MEM_COPY_ATTRIBUTES (DECL_RTL (decl_elt), x);
RTX_UNCHANGING_P (DECL_RTL (decl_elt)) = RTX_UNCHANGING_P (x);
}
}
@@ -3857,7 +4153,7 @@ expand_start_case (exit_flag, expr, type, printname)
int exit_flag;
tree expr;
tree type;
- char *printname;
+ const char *printname;
{
register struct nesting *thiscase = ALLOC_NESTING ();
@@ -4705,7 +5001,7 @@ void
expand_end_case (orig_index)
tree orig_index;
{
- tree minval, maxval, range, orig_minval;
+ tree minval = NULL_TREE, maxval = NULL_TREE, range, orig_minval;
rtx default_label = 0;
register struct case_node *n;
unsigned int count;
@@ -4833,7 +5129,7 @@ expand_end_case (orig_index)
#endif /* CASE_VALUES_THRESHOLD */
else if (TREE_INT_CST_HIGH (range) != 0
- || count < CASE_VALUES_THRESHOLD
+ || count < (unsigned int) CASE_VALUES_THRESHOLD
|| ((unsigned HOST_WIDE_INT) (TREE_INT_CST_LOW (range))
> 10 * count)
#ifndef ASM_OUTPUT_ADDR_DIFF_ELT
@@ -4953,8 +5249,8 @@ expand_end_case (orig_index)
index_expr, minval);
minval = integer_zero_node;
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
- emit_cmp_insn (rangertx, index, LTU, NULL_RTX, omode, 1, 0);
- emit_jump_insn (gen_bltu (default_label));
+ emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
+ omode, 1, 0, default_label);
/* Now we can safely truncate. */
index = convert_to_mode (index_mode, index, 0);
}
@@ -5123,8 +5419,8 @@ do_jump_if_equal (op1, op2, label, unsignedp)
enum machine_mode mode = GET_MODE (op1);
if (mode == VOIDmode)
mode = GET_MODE (op2);
- emit_cmp_insn (op1, op2, EQ, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn (gen_beq (label));
+ emit_cmp_and_jump_insns (op1, op2, EQ, NULL_RTX, mode, unsignedp,
+ 0, label);
}
}
@@ -5532,11 +5828,7 @@ emit_case_nodes (index, node, default_label, index_type)
{
/* If INDEX has an unsigned type, we must make unsigned branches. */
int unsignedp = TREE_UNSIGNED (index_type);
- typedef rtx rtx_function ();
- rtx_function *gen_bgt_pat = unsignedp ? gen_bgtu : gen_bgt;
- rtx_function *gen_bge_pat = unsignedp ? gen_bgeu : gen_bge;
- rtx_function *gen_blt_pat = unsignedp ? gen_bltu : gen_blt;
- rtx_function *gen_ble_pat = unsignedp ? gen_bleu : gen_ble;
+ typedef rtx rtx_fn ();
enum machine_mode mode = GET_MODE (index);
/* See if our parents have already tested everything for us.
@@ -5562,20 +5854,19 @@ emit_case_nodes (index, node, default_label, index_type)
if (node_is_bounded (node->right, index_type))
{
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- GT, NULL_RTX, mode, unsignedp, 0);
-
- emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ 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_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- LT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_blt_pat) (label_rtx (node->left->code_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ LT, NULL_RTX, mode, unsignedp, 0,
+ label_rtx (node->left->code_label));
emit_case_nodes (index, node->right, default_label, index_type);
}
@@ -5588,10 +5879,10 @@ emit_case_nodes (index, node, default_label, index_type)
= build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
/* See if the value is on the right. */
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- GT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_bgt_pat) (label_rtx (test_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ label_rtx (test_label));
/* Value must be on the left.
Handle the left-hand subtree. */
@@ -5619,10 +5910,11 @@ emit_case_nodes (index, node, default_label, index_type)
{
if (!node_has_low_bound (node, index_type))
{
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- LT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_blt_pat) (default_label));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high,
+ NULL_RTX,
+ VOIDmode, 0),
+ LT, NULL_RTX, mode, unsignedp, 0,
+ default_label);
}
emit_case_nodes (index, node->right, default_label, index_type);
@@ -5659,10 +5951,11 @@ emit_case_nodes (index, node, default_label, index_type)
{
if (!node_has_high_bound (node, index_type))
{
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- GT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_bgt_pat) (default_label));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high,
+ NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ default_label);
}
emit_case_nodes (index, node->left, default_label, index_type);
@@ -5692,28 +5985,32 @@ emit_case_nodes (index, node, default_label, index_type)
then handle the two subtrees. */
tree test_label = 0;
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- GT, NULL_RTX, mode, unsignedp, 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_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ 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_jump_insn ((*gen_bgt_pat) (label_rtx (test_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ label_rtx (test_label));
}
/* Value belongs to this node or to the left-hand subtree. */
- emit_cmp_insn (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
- GE, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ GE, NULL_RTX, mode, unsignedp, 0,
+ label_rtx (node->code_label));
/* Handle the left-hand subtree. */
emit_case_nodes (index, node->left, default_label, index_type);
@@ -5737,18 +6034,18 @@ emit_case_nodes (index, node, default_label, index_type)
if they are possible. */
if (!node_has_low_bound (node, index_type))
{
- emit_cmp_insn (index, expand_expr (node->low, NULL_RTX,
- VOIDmode, 0),
- LT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_blt_pat) (default_label));
+ emit_cmp_and_jump_insns (index, expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ LT, NULL_RTX, mode, unsignedp, 0,
+ default_label);
}
/* Value belongs to this node or to the right-hand subtree. */
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- LE, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_ble_pat) (label_rtx (node->code_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ LE, NULL_RTX, mode, unsignedp, 0,
+ label_rtx (node->code_label));
emit_case_nodes (index, node->right, default_label, index_type);
}
@@ -5759,17 +6056,18 @@ emit_case_nodes (index, node, default_label, index_type)
if they are possible. */
if (!node_has_high_bound (node, index_type))
{
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- GT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_bgt_pat) (default_label));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ default_label);
}
/* Value belongs to this node or to the left-hand subtree. */
- emit_cmp_insn (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
- GE, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
+ emit_cmp_and_jump_insns (index, expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ GE, NULL_RTX, mode, unsignedp, 0,
+ label_rtx (node->code_label));
emit_case_nodes (index, node->left, default_label, index_type);
}
@@ -5782,18 +6080,18 @@ emit_case_nodes (index, node, default_label, index_type)
if (!node_has_high_bound (node, index_type))
{
- emit_cmp_insn (index, expand_expr (node->high, NULL_RTX,
- VOIDmode, 0),
- GT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_bgt_pat) (default_label));
+ emit_cmp_and_jump_insns (index, expand_expr (node->high, NULL_RTX,
+ VOIDmode, 0),
+ GT, NULL_RTX, mode, unsignedp, 0,
+ default_label);
}
if (!node_has_low_bound (node, index_type))
{
- emit_cmp_insn (index, expand_expr (node->low, NULL_RTX,
- VOIDmode, 0),
- LT, NULL_RTX, mode, unsignedp, 0);
- emit_jump_insn ((*gen_blt_pat) (default_label));
+ emit_cmp_and_jump_insns (index, expand_expr (node->low, NULL_RTX,
+ VOIDmode, 0),
+ LT, NULL_RTX, mode, unsignedp, 0,
+ default_label);
}
emit_jump (label_rtx (node->code_label));
OpenPOWER on IntegriCloud