#include "expr.h"
#include "libfuncs.h"
#include "hard-reg-set.h"
-#include "obstack.h"
#include "loop.h"
#include "recog.h"
#include "machmode.h"
#include "output.h"
#include "ggc.h"
#include "langhooks.h"
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-struct obstack stmt_obstack;
+#include "predict.h"
/* Assume that case vectors are not pc-relative. */
#ifndef CASE_VECTOR_PC_RELATIVE
and nodes on the right having higher values. We then output the tree
in order. */
-struct case_node
+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 */
The construct is visible if the `exit_label' field is non-null.
In that case, the value should be a CODE_LABEL rtx. */
-struct nesting
+struct nesting GTY(())
{
struct nesting *all;
struct nesting *next;
int depth;
rtx exit_label;
- union
+ enum nesting_desc {
+ COND_NESTING,
+ LOOP_NESTING,
+ BLOCK_NESTING,
+ CASE_NESTING
+ } desc;
+ union nesting_u
{
/* For conds (if-then and if-then-else statements). */
- struct
+ struct nesting_cond
{
/* Label for the end of the if construct.
There is none if EXITFLAG was not set
/* Label for the end of this alternative.
This may be the end of the if or the next else/elseif. */
rtx next_label;
- } cond;
+ } GTY ((tag ("COND_NESTING"))) cond;
/* For loops. */
- struct
+ struct nesting_loop
{
/* Label at the top of the loop; place to loop back to. */
rtx start_label;
/* Label for `continue' statement to jump to;
this is in front of the stepper of the loop. */
rtx continue_label;
- } loop;
+ } GTY ((tag ("LOOP_NESTING"))) loop;
/* For variable binding contours. */
- struct
+ struct nesting_block
{
/* Sequence number of this binding contour within the function,
in order of entry. */
struct label_chain *label_chain;
/* Number of function calls seen, as of start of this block. */
int n_function_calls;
- /* Nonzero if this is associated with a EH region. */
+ /* Nonzero if this is associated with an EH region. */
int exception_region;
/* The saved target_temp_slot_level from our outer block.
We may reset target_temp_slot_level to be the level of
the start of the last unconditional cleanup, and before any
conditional branch points. */
rtx last_unconditional_cleanup;
- /* When in a conditional context, this is the specific
- cleanup list associated with last_unconditional_cleanup,
- where we place the conditionalized cleanups. */
- tree *cleanup_ptr;
- } block;
+ } GTY ((tag ("BLOCK_NESTING"))) block;
/* For switch (C) or case (Pascal) statements,
and also for dummies (see `expand_start_case_dummy'). */
- struct
+ struct nesting_case
{
/* The insn after which the case dispatch should finally
be emitted. Zero for a dummy. */
We set this to -1 when we see the first case label in this
case statement. */
int line_number_status;
- } case_stmt;
- } data;
+ } GTY ((tag ("CASE_NESTING"))) case_stmt;
+ } GTY ((desc ("%1.desc"))) data;
};
/* Allocate and return a new `struct nesting'. */
#define ALLOC_NESTING() \
- (struct nesting *) obstack_alloc (&stmt_obstack, sizeof (struct nesting))
+ (struct nesting *) ggc_alloc (sizeof (struct nesting))
/* Pop the nesting stack element by element until we pop off
the element which is at the top of STACK.
if (case_stack == this) \
case_stack = case_stack->next; \
nesting_depth = nesting_stack->depth - 1; \
- nesting_stack = this->all; \
- obstack_free (&stmt_obstack, this); } \
+ nesting_stack = this->all; } \
while (this != target); } while (0)
\f
/* In some cases it is impossible to generate code for a forward goto
we check each fixup.
If the target label has now been defined, we can insert the proper code. */
-struct goto_fixup
+struct goto_fixup GTY(())
{
/* Points to following fixup. */
struct goto_fixup *next;
/* Within any binding contour that must restore a stack level,
all labels are recorded with a chain of these structures. */
-struct label_chain
+struct label_chain GTY(())
{
/* Points to following fixup. */
struct label_chain *next;
tree label;
};
-struct stmt_status
+struct stmt_status GTY(())
{
/* Chain of all pending binding contours. */
- struct nesting *x_block_stack;
+ struct nesting * x_block_stack;
/* If any new stacks are added here, add them to POPSTACKS too. */
/* Chain of all pending binding contours that restore stack levels
or have cleanups. */
- struct nesting *x_stack_block_stack;
+ struct nesting * x_stack_block_stack;
/* Chain of all pending conditional statements. */
- struct nesting *x_cond_stack;
+ struct nesting * x_cond_stack;
/* Chain of all pending loops. */
- struct nesting *x_loop_stack;
+ struct nesting * x_loop_stack;
/* Chain of all pending case or switch statements. */
- struct nesting *x_case_stack;
+ struct nesting * x_case_stack;
/* Separate chain including all of the above,
chained through the `all' field. */
- struct nesting *x_nesting_stack;
+ struct nesting * x_nesting_stack;
/* Number of entries on nesting_stack now. */
int x_nesting_depth;
const char **));
static char *resolve_operand_name_1 PARAMS ((char *, tree, tree));
static void expand_null_return_1 PARAMS ((rtx));
+static enum br_predictor return_prediction PARAMS ((rtx));
static void expand_value_return PARAMS ((rtx));
static int tail_recursion_args PARAMS ((tree, tree));
static void expand_cleanups PARAMS ((tree, tree, int, int));
static void emit_jump_if_reachable PARAMS ((rtx));
static void emit_case_nodes PARAMS ((rtx, case_node_ptr, rtx, tree));
static struct case_node *case_tree2list PARAMS ((case_node *, case_node *));
-static void mark_cond_nesting PARAMS ((struct nesting *));
-static void mark_loop_nesting PARAMS ((struct nesting *));
-static void mark_block_nesting PARAMS ((struct nesting *));
-static void mark_case_nesting PARAMS ((struct nesting *));
-static void mark_case_node PARAMS ((struct case_node *));
-static void mark_goto_fixup PARAMS ((struct goto_fixup *));
-static void free_case_nodes PARAMS ((case_node_ptr));
\f
void
using_eh_for_cleanups ()
using_eh_for_cleanups_p = 1;
}
-/* Mark N (known to be a cond-nesting) for GC. */
-
-static void
-mark_cond_nesting (n)
- struct nesting *n;
-{
- while (n)
- {
- ggc_mark_rtx (n->exit_label);
- ggc_mark_rtx (n->data.cond.endif_label);
- ggc_mark_rtx (n->data.cond.next_label);
-
- n = n->next;
- }
-}
-
-/* Mark N (known to be a loop-nesting) for GC. */
-
-static void
-mark_loop_nesting (n)
- struct nesting *n;
-{
-
- while (n)
- {
- ggc_mark_rtx (n->exit_label);
- ggc_mark_rtx (n->data.loop.start_label);
- ggc_mark_rtx (n->data.loop.end_label);
- ggc_mark_rtx (n->data.loop.alt_end_label);
- ggc_mark_rtx (n->data.loop.continue_label);
-
- n = n->next;
- }
-}
-
-/* Mark N (known to be a block-nesting) for GC. */
-
-static void
-mark_block_nesting (n)
- struct nesting *n;
-{
- while (n)
- {
- struct label_chain *l;
-
- ggc_mark_rtx (n->exit_label);
- ggc_mark_rtx (n->data.block.stack_level);
- ggc_mark_rtx (n->data.block.first_insn);
- ggc_mark_tree (n->data.block.cleanups);
- ggc_mark_tree (n->data.block.outer_cleanups);
-
- for (l = n->data.block.label_chain; l != NULL; l = l->next)
- {
- ggc_mark (l);
- ggc_mark_tree (l->label);
- }
-
- ggc_mark_rtx (n->data.block.last_unconditional_cleanup);
-
- /* ??? cleanup_ptr never points outside the stack, does it? */
-
- n = n->next;
- }
-}
-
-/* Mark N (known to be a case-nesting) for GC. */
-
-static void
-mark_case_nesting (n)
- struct nesting *n;
-{
- while (n)
- {
- ggc_mark_rtx (n->exit_label);
- ggc_mark_rtx (n->data.case_stmt.start);
-
- ggc_mark_tree (n->data.case_stmt.default_label);
- ggc_mark_tree (n->data.case_stmt.index_expr);
- ggc_mark_tree (n->data.case_stmt.nominal_type);
-
- mark_case_node (n->data.case_stmt.case_list);
- n = n->next;
- }
-}
-
-/* Mark C for GC. */
-
-static void
-mark_case_node (c)
- struct case_node *c;
-{
- if (c != 0)
- {
- ggc_mark_tree (c->low);
- ggc_mark_tree (c->high);
- ggc_mark_tree (c->code_label);
-
- mark_case_node (c->right);
- mark_case_node (c->left);
- }
-}
-
-/* Mark G for GC. */
-
-static void
-mark_goto_fixup (g)
- struct goto_fixup *g;
-{
- while (g)
- {
- ggc_mark (g);
- ggc_mark_rtx (g->before_jump);
- ggc_mark_tree (g->target);
- ggc_mark_tree (g->context);
- ggc_mark_rtx (g->target_rtl);
- ggc_mark_rtx (g->stack_level);
- ggc_mark_tree (g->cleanup_list_list);
-
- g = g->next;
- }
-}
-
-/* Clear out all parts of the state in F that can safely be discarded
- after the function has been compiled, to let garbage collection
- reclaim the memory. */
-
-void
-free_stmt_status (f)
- struct function *f;
-{
- /* We're about to free the function obstack. If we hold pointers to
- things allocated there, then we'll try to mark them when we do
- GC. So, we clear them out here explicitly. */
- if (f->stmt)
- free (f->stmt);
- f->stmt = NULL;
-}
-
-/* Mark P for GC. */
-
-void
-mark_stmt_status (p)
- struct stmt_status *p;
-{
- if (p == 0)
- return;
-
- mark_block_nesting (p->x_block_stack);
- mark_cond_nesting (p->x_cond_stack);
- mark_loop_nesting (p->x_loop_stack);
- mark_case_nesting (p->x_case_stack);
-
- ggc_mark_tree (p->x_last_expr_type);
- /* last_epxr_value is only valid if last_expr_type is nonzero. */
- if (p->x_last_expr_type)
- ggc_mark_rtx (p->x_last_expr_value);
-
- mark_goto_fixup (p->x_goto_fixup_chain);
-}
-
-void
-init_stmt ()
-{
- gcc_obstack_init (&stmt_obstack);
-}
-
void
init_stmt_for_function ()
{
- cfun->stmt = (struct stmt_status *) xmalloc (sizeof (struct stmt_status));
+ cfun->stmt = ((struct stmt_status *)ggc_alloc (sizeof (struct stmt_status)));
/* We are not currently within any block, conditional, loop or case. */
block_stack = 0;
/* We are not processing a ({...}) grouping. */
expr_stmts_for_value = 0;
- last_expr_type = 0;
- last_expr_value = NULL_RTX;
+ clear_last_expr ();
}
\f
/* Return nonzero if anything is pushed on the loop, condition, or case
emit_indirect_jump (handler_slot);
}
- /* Search backwards to the jump insn and mark it as a
+ /* Search backwards to the jump insn and mark it as a
non-local goto. */
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
as a placeholder. */
{
- rtx original_before_jump
- = last_insn ? last_insn : get_last_insn ();
+ rtx original_before_jump
+ = last_insn ? last_insn : get_last_insn ();
rtx start;
rtx end;
tree block;
= block;
}
- start_sequence ();
- start = emit_note (NULL, NOTE_INSN_BLOCK_BEG);
+ start_sequence ();
+ start = emit_note (NULL, NOTE_INSN_BLOCK_BEG);
if (cfun->x_whole_function_mode_p)
NOTE_BLOCK (start) = block;
fixup->before_jump = emit_note (NULL, NOTE_INSN_DELETED);
end = emit_note (NULL, NOTE_INSN_BLOCK_END);
if (cfun->x_whole_function_mode_p)
NOTE_BLOCK (end) = block;
- fixup->context = block;
- end_sequence ();
- emit_insns_after (start, original_before_jump);
+ fixup->context = block;
+ end_sequence ();
+ emit_insn_after (start, original_before_jump);
}
fixup->block_start_count = current_block_start_count;
(*lang_hooks.decls.poplevel) (1, 0, 0);
end_sequence ();
- emit_insns_after (cleanup_insns, f->before_jump);
+ emit_insn_after (cleanup_insns, f->before_jump);
f->before_jump = 0;
}
end_sequence ();
if (cleanup_insns != 0)
f->before_jump
- = emit_insns_after (cleanup_insns, f->before_jump);
+ = emit_insn_after (cleanup_insns, f->before_jump);
f->cleanup_list_list = TREE_CHAIN (lists);
}
emit_insn (gen_rtx_ASM_INPUT (VOIDmode,
TREE_STRING_POINTER (body)));
- last_expr_type = 0;
+ clear_last_expr ();
}
/* Parse the output constraint pointed to by *CONSTRAINT_P. It is the
case '=':
error ("operand constraint contains incorrectly positioned '+' or '='");
return false;
-
+
case '%':
if (operand_num + 1 == ninputs + noutputs)
{
*allows_reg = true;
*allows_mem = true;
break;
-
+
case 'p': case 'r':
*allows_reg = true;
break;
if (REG_CLASS_FROM_LETTER (*p) != NO_REGS)
*allows_reg = true;
#ifdef EXTRA_CONSTRAINT
+ else if (EXTRA_ADDRESS_CONSTRAINT (*p))
+ *allows_reg = true;
+ else if (EXTRA_MEMORY_CONSTRAINT (*p))
+ *allows_mem = true;
else
{
/* Otherwise we can't assume anything about the nature of
if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
*allows_reg = true;
#ifdef EXTRA_CONSTRAINT
+ else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j]))
+ *allows_reg = true;
+ else if (EXTRA_MEMORY_CONSTRAINT (constraint[j]))
+ *allows_mem = true;
else
{
/* Otherwise we can't assume anything about the nature of
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
+ 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.
error ("unknown register name `%s' in `asm'", regname);
}
- last_expr_type = 0;
+ clear_last_expr ();
/* First pass over inputs and outputs checks validity and sets
mark_addressable if needed. */
if ((! allows_mem && GET_CODE (output_rtx[i]) == MEM)
|| GET_CODE (output_rtx[i]) == CONCAT)
{
- real_output_rtx[i] = protect_from_queue (output_rtx[i], 1);
+ 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]);
body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
: GET_MODE (output_rtx[0])),
- TREE_STRING_POINTER (string),
+ TREE_STRING_POINTER (string),
empty_string, 0, argvec, constraintvec,
filename, line);
continue;
for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
- if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+ if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
goto failure;
}
continue;
for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
- if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+ if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
goto failure;
for (j = outputs; j ; j = TREE_CHAIN (j))
- if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+ if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
goto failure;
}
failure:
error ("duplicate asm operand name '%s'",
- IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
+ TREE_STRING_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
return false;
}
/* 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
+ the name and brackets with a number. Return a pointer to the
balance of the string after substitution. */
static char *
/* Resolve the name to a number. */
for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
{
- tree id = TREE_PURPOSE (TREE_PURPOSE (t));
- if (id)
+ tree name = TREE_PURPOSE (TREE_PURPOSE (t));
+ if (name)
{
- const char *c = IDENTIFIER_POINTER (id);
+ 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 id = TREE_PURPOSE (TREE_PURPOSE (t));
- if (id)
+ tree name = TREE_PURPOSE (TREE_PURPOSE (t));
+ if (name)
{
- const char *c = IDENTIFIER_POINTER (id);
+ const char *c = TREE_STRING_POINTER (name);
if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
goto found;
}
void
clear_last_expr ()
{
- last_expr_type = 0;
+ last_expr_type = NULL_TREE;
+ last_expr_value = NULL_RTX;
}
-/* Begin a statement which will return a value.
- Return the RTL_EXPR for this statement expr.
- The caller must save that value and pass it to expand_end_stmt_expr. */
+/* Begin a statement-expression, i.e., a series of statements which
+ may return a value. Return the RTL_EXPR for this statement expr.
+ The caller must save that value and pass it to
+ expand_end_stmt_expr. If HAS_SCOPE is nonzero, temporaries created
+ in the statement-expression are deallocated at the end of the
+ expression. */
tree
-expand_start_stmt_expr ()
+expand_start_stmt_expr (has_scope)
+ int has_scope;
{
tree t;
so that rtl_expr_chain doesn't become garbage. */
t = make_node (RTL_EXPR);
do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (t);
+ if (has_scope)
+ start_sequence_for_rtl_expr (t);
+ else
+ start_sequence ();
NO_DEFER_POP;
expr_stmts_for_value++;
- last_expr_value = NULL_RTX;
return t;
}
/* Propagate volatility of the actual RTL expr. */
TREE_THIS_VOLATILE (t) = volatile_refs_p (last_expr_value);
- last_expr_type = 0;
+ clear_last_expr ();
expr_stmts_for_value--;
return t;
/* Make an entry on cond_stack for the cond we are entering. */
+ thiscond->desc = COND_NESTING;
thiscond->next = cond_stack;
thiscond->all = nesting_stack;
thiscond->depth = ++nesting_depth;
emit_label (thiscond->data.cond.endif_label);
POPSTACK (cond_stack);
- last_expr_type = 0;
+ clear_last_expr ();
}
\f
/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this
/* Make an entry on loop_stack for the loop we are entering. */
+ thisloop->desc = LOOP_NESTING;
thisloop->next = loop_stack;
thisloop->all = nesting_stack;
thisloop->depth = ++nesting_depth;
/* Make an entry on loop_stack for the loop we are entering. */
+ thisloop->desc = LOOP_NESTING;
thisloop->next = loop_stack;
thisloop->all = nesting_stack;
thisloop->depth = ++nesting_depth;
the end of the entry condtional. Without this, our lexical scan
can't tell the difference between an entry conditional and a
body conditional that exits the loop. Mistaking the two means
- that we can misplace the NOTE_INSN_LOOP_CONT note, which can
+ that we can misplace the NOTE_INSN_LOOP_CONT note, which can
screw up loop unrolling.
Things will be oh so much better when loop optimization is done
/* Likewise for debug scopes. In this case we'll either (1) move
all of the notes if they are properly nested or (2) leave the
- notes alone and only rotate the loop at high optimization
+ notes alone and only rotate the loop at high optimization
levels when we expect to scrog debug info. */
else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_BEG)
debug_blocks++;
POPSTACK (loop_stack);
- last_expr_type = 0;
+ clear_last_expr ();
}
/* Finish a null loop, aka do { } while (0). */
POPSTACK (loop_stack);
- last_expr_type = 0;
+ clear_last_expr ();
}
/* Generate a jump to the current loop's continue-point.
expand_continue_loop (whichloop)
struct nesting *whichloop;
{
- last_expr_type = 0;
+ /* Emit information for branch prediction. */
+ rtx note;
+
+ note = emit_note (NULL, NOTE_INSN_PREDICTION);
+ NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
+ clear_last_expr ();
if (whichloop == 0)
whichloop = loop_stack;
if (whichloop == 0)
expand_exit_loop (whichloop)
struct nesting *whichloop;
{
- last_expr_type = 0;
+ clear_last_expr ();
if (whichloop == 0)
whichloop = loop_stack;
if (whichloop == 0)
{
rtx label = gen_label_rtx ();
rtx last_insn;
- last_expr_type = 0;
+ clear_last_expr ();
if (whichloop == 0)
whichloop = loop_stack;
}
/* Like expand_exit_loop_if_false except also emit a note marking
- the end of the conditional. Should only be used immediately
+ the end of the conditional. Should only be used immediately
after expand_loop_start. */
int
expand_exit_something ()
{
struct nesting *n;
- last_expr_type = 0;
+ clear_last_expr ();
for (n = nesting_stack; n; n = n->all)
if (n->exit_label != 0)
{
void
expand_null_return ()
{
- rtx last_insn = get_last_insn ();
+ rtx last_insn;
+
+ last_insn = get_last_insn ();
/* If this function was declared to return a value, but we
didn't, clobber the return registers so that they are not
expand_null_return_1 (last_insn);
}
+/* Try to guess whether the value of return means error code. */
+static enum br_predictor
+return_prediction (val)
+ rtx val;
+{
+ /* Different heuristics for pointers and scalars. */
+ if (POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
+ {
+ /* NULL is usually not returned. */
+ if (val == const0_rtx)
+ return PRED_NULL_RETURN;
+ }
+ else
+ {
+ /* Negative return values are often used to indicate
+ errors. */
+ if (GET_CODE (val) == CONST_INT
+ && INTVAL (val) < 0)
+ return PRED_NEGATIVE_RETURN;
+ /* Constant return values are also usually erors,
+ zero/one often mean booleans so exclude them from the
+ heuristics. */
+ if (CONSTANT_P (val)
+ && (val != const0_rtx && val != const1_rtx))
+ return PRED_CONST_RETURN;
+ }
+ return PRED_NO_PREDICTION;
+}
+
/* Generate RTL to return from the current function, with value VAL. */
static void
expand_value_return (val)
rtx val;
{
- rtx last_insn = get_last_insn ();
- rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
+ rtx last_insn;
+ rtx return_reg;
+ enum br_predictor pred;
+
+ if ((pred = return_prediction (val)) != PRED_NO_PREDICTION)
+ {
+ /* Emit information for branch prediction. */
+ rtx note;
+
+ note = emit_note (NULL, NOTE_INSN_PREDICTION);
+
+ NOTE_PREDICTION (note) = NOTE_PREDICT (pred, NOT_TAKEN);
+
+ }
+
+ last_insn = get_last_insn ();
+ return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
/* Copy the value to the return location
unless it's already there. */
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
- last_expr_type = 0;
+ clear_last_expr ();
if (end_label == 0)
end_label = return_label = gen_label_rtx ();
/* Treat this like a return of no value from a function that
returns a value. */
expand_null_return ();
- return;
+ return;
}
else if (TREE_CODE (retval) == RESULT_DECL)
retval_rhs = retval;
/* Make an entry on block_stack for the block we are entering. */
+ thisblock->desc = BLOCK_NESTING;
thisblock->next = block_stack;
thisblock->all = nesting_stack;
thisblock->depth = ++nesting_depth;
instructions inserted after the last unconditional cleanup are
never the last instruction. */
emit_note (NULL, NOTE_INSN_DELETED);
- thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
if (block_stack
&& !(block_stack->data.block.cleanups == NULL_TREE
emit_move_insn (slot, gen_rtx_LABEL_REF (Pmode, handler_label));
insns = get_insns ();
end_sequence ();
- emit_insns_before (insns, before_insn);
+ emit_insn_before (insns, before_insn);
emit_label (handler_label);
emit_move_insn (save_receiver, XEXP (slot, 0));
insns = get_insns ();
end_sequence ();
- emit_insns_before (insns, thisblock->data.block.first_insn);
+ emit_insn_before (insns, thisblock->data.block.first_insn);
}
/* Jump around the handlers; they run only when specially invoked. */
: GET_MODE_BITSIZE (DECL_MODE (decl)));
DECL_USER_ALIGN (decl) = 0;
- x = assign_temp (TREE_TYPE (decl), 1, 1, 1);
+ x = assign_temp (decl, 1, 1, 1);
set_mem_attributes (x, decl, 1);
SET_DECL_RTL (decl, x);
end_sequence ();
thisblock->data.block.last_unconditional_cleanup
- = emit_insns_after (set_flag_0,
+ = emit_insn_after (set_flag_0,
thisblock->data.block.last_unconditional_cleanup);
emit_move_insn (flag, const1_rtx);
/* Conditionalize the cleanup. */
cleanup = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
+ (*lang_hooks.truthvalue_conversion) (cond),
cleanup, integer_zero_node);
cleanup = fold (cleanup);
- cleanups = thisblock->data.block.cleanup_ptr;
+ cleanups = &thisblock->data.block.cleanups;
}
cleanup = unsave_expr (cleanup);
end_sequence ();
if (seq)
thisblock->data.block.last_unconditional_cleanup
- = emit_insns_after (seq,
- thisblock->data.block.last_unconditional_cleanup);
+ = emit_insn_after (seq,
+ thisblock->data.block.last_unconditional_cleanup);
}
else
{
instructions inserted after the last unconditional cleanup are
never the last instruction. */
emit_note (NULL, NOTE_INSN_DELETED);
- thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
}
}
return 1;
}
+
+/* Like expand_decl_cleanup, but maybe only run the cleanup if an exception
+ is thrown. */
+
+int
+expand_decl_cleanup_eh (decl, cleanup, eh_only)
+ tree decl, cleanup;
+ int eh_only;
+{
+ int ret = expand_decl_cleanup (decl, cleanup);
+ if (cleanup && ret)
+ {
+ tree node = block_stack->data.block.cleanups;
+ CLEANUP_EH_ONLY (node) = eh_only;
+ }
+ return ret;
+}
\f
/* DECL is an anonymous union. CLEANUP is a cleanup for DECL.
DECL_ELTS is the list of elements that belong to DECL's type.
if (! in_fixup && using_eh_for_cleanups_p)
expand_eh_region_end_cleanup (TREE_VALUE (tail));
- if (reachable)
+ if (reachable && !CLEANUP_EH_ONLY (tail))
{
/* Cleanups may be run multiple times. For example,
when exiting a binding contour, we expand the
/* Make an entry on case_stack for the case we are entering. */
+ thiscase->desc = CASE_NESTING;
thiscase->next = case_stack;
thiscase->all = nesting_stack;
thiscase->depth = ++nesting_depth;
/* Make an entry on case_stack for the dummy. */
+ thiscase->desc = CASE_NESTING;
thiscase->next = case_stack;
thiscase->all = nesting_stack;
thiscase->depth = ++nesting_depth;
/* Add this label to the chain, and succeed. */
- r = (struct case_node *) xmalloc (sizeof (struct case_node));
+ r = (struct case_node *) ggc_alloc (sizeof (struct case_node));
r->low = low;
/* If the bounds are equal, turn this into the one-value case. */
/* The time complexity of this code is normally O(N), where
N being the number of members in the enumerated type.
- However, if type is a ENUMERAL_TYPE whose values do not
+ However, if type is an ENUMERAL_TYPE whose values do not
increase monotonically, O(N*log(N)) time may be needed. */
mark_seen_cases (type, cases_seen, size, sparseness);
chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
chain = TREE_CHAIN (chain))
;
-
+
if (!chain)
{
if (TYPE_NAME (type) == 0)
chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain));
chain = TREE_CHAIN (chain))
;
-
+
if (!chain)
{
if (TYPE_NAME (type) == 0)
}
}
-/* Free CN, and its children. */
-
-static void
-free_case_nodes (cn)
- case_node_ptr cn;
-{
- if (cn)
- {
- free_case_nodes (cn->left);
- free_case_nodes (cn->right);
- free (cn);
- }
-}
-
\f
/* Terminate a case (Pascal) or switch (C) statement
{
index_type = thiscase->data.case_stmt.nominal_type;
- /* Index jumptables from zero for suitable values of
+ /* 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 = integer_zero_node;
- range = maxval;
- }
+ if (! optimize_size
+ && compare_tree_int (minval, 0) > 0
+ && compare_tree_int (minval, 3) < 0)
+ {
+ minval = integer_zero_node;
+ range = maxval;
+ }
if (! try_tablejump (index_type, index_expr, minval, range,
table_label, default_label))
abort ();
}
-
+
/* Get table of labels to jump to, in order of case index. */
ncases = tree_low_cst (range, 0) + 1;
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 (build (MINUS_EXPR, index_type,
- n->low, minval)), 1);
+ = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+ n->low, minval)), 1);
HOST_WIDE_INT i_high
- = tree_low_cst (fold (build (MINUS_EXPR, index_type,
- n->high, minval)), 1);
+ = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+ n->high, minval)), 1);
HOST_WIDE_INT i;
for (i = i_low; i <= i_high; i ++)
if (thiscase->exit_label)
emit_label (thiscase->exit_label);
- free_case_nodes (case_stack->data.case_stmt.case_list);
POPSTACK (case_stack);
free_temp_slots ();
new_bound = expand_expr (fold (build (MINUS_EXPR, type,
high, low)),
NULL_RTX, mode, 0);
-
+
emit_cmp_and_jump_insns (new_index, new_bound, GT, NULL_RTX,
mode, 1, default_label);
}
}
}
}
+
+#include "gt-stmt.h"