/* This must be a signed type, and non-ANSI compilers lack signed char. */
static short cost_table_[129];
-static short *cost_table;
static int use_cost_table;
+static int cost_table_initialized;
+
+/* Special care is needed because we allow -1, but TREE_INT_CST_LOW
+ is unsigned. */
+#define COST_TABLE(I) cost_table_[(unsigned HOST_WIDE_INT)((I) + 1)]
\f
/* Stack of control and binding constructs we are currently inside.
/* Non-zero if we are using EH to handle cleanus. */
static int using_eh_for_cleanups_p = 0;
-/* Character strings, each containing a single decimal digit. */
-static char *digit_strings[10];
-
static int n_occurrences PARAMS ((int, const char *));
static void expand_goto_internal PARAMS ((tree, rtx, rtx));
static int expand_fixup PARAMS ((tree, rtx, rtx));
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 ()
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_tree (l->label);
+ 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);
void
init_stmt ()
{
- int i;
-
gcc_obstack_init (&stmt_obstack);
-
- for (i = 0; i < 10; i++)
- {
- digit_strings[i] = ggc_alloc_string (NULL, 1);
- digit_strings[i][0] = '0' + i;
- }
- ggc_add_string_root (digit_strings, 10);
}
void
emit_queue ();
/* Be sure the function is executable. */
if (current_function_check_memory_usage)
- emit_library_call (chkr_check_exec_libfunc, 1,
+ emit_library_call (chkr_check_exec_libfunc, LCT_CONST_MAKE_BLOCK,
VOIDmode, 1, x, ptr_mode);
do_pending_stack_adjust ();
if (stack_block_stack != 0)
{
- p = (struct label_chain *) oballoc (sizeof (struct label_chain));
+ p = (struct label_chain *) ggc_alloc (sizeof (struct label_chain));
p->next = stack_block_stack->data.block.label_chain;
stack_block_stack->data.block.label_chain = p;
p->label = label;
{
struct function *p = find_function_data (context);
rtx label_ref = gen_rtx_LABEL_REF (Pmode, label_rtx (label));
- rtx handler_slot, static_chain, save_area;
+ rtx handler_slot, static_chain, save_area, insn;
tree link;
/* Find the corresponding handler slot for this label. */
emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
emit_indirect_jump (handler_slot);
}
+
+ /* Search backwards to the jump insn and mark it as a
+ non-local goto. */
+ for (insn = get_last_insn ();
+ GET_CODE (insn) != JUMP_INSN;
+ insn = PREV_INSN (insn))
+ continue;
+ REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
+ REG_NOTES (insn));
}
else
expand_goto_internal (label, label_rtx (label), NULL_RTX);
{
tree val = TREE_VALUE (tail);
tree type = TREE_TYPE (val);
- char *constraint;
+ const char *constraint;
char *p;
int c_len;
int j;
the worst that happens if we get it wrong is we issue an error
message. */
- c_len = strlen (TREE_STRING_POINTER (TREE_PURPOSE (tail)));
constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+ c_len = strlen (constraint);
/* Allow the `=' or `+' to not be at the beginning of the string,
since it wasn't explicitly documented that way, and there is a
error ("output operand constraint lacks `='");
return;
}
+ j = p - constraint;
+ is_inout = *p == '+';
- if (p != constraint)
+ if (j || is_inout)
{
- j = *p;
- bcopy (constraint, constraint+1, p-constraint);
- *constraint = j;
-
- warning ("output constraint `%c' for operand %d is not at the beginning", j, i);
+ /* Have to throw away this constraint string and get a new one. */
+ char *buf = alloca (c_len + 1);
+ buf[0] = '=';
+ if (j)
+ memcpy (buf + 1, constraint, j);
+ memcpy (buf + 1 + j, p + 1, c_len - j); /* not -j-1 - copy null */
+ constraint = ggc_alloc_string (buf, c_len);
+
+ if (j)
+ warning (
+ "output constraint `%c' for operand %d is not at the beginning",
+ *p, i);
}
- is_inout = constraint[0] == '+';
- /* Replace '+' with '='. */
- constraint[0] = '=';
/* Make sure we can specify the matching operand. */
if (is_inout && i > 9)
{
}
break;
- case '?': case '!': case '*': case '&':
+ case '?': case '!': case '*': case '&': case '#':
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L': case 'M':
{
int j;
int allows_reg = 0, allows_mem = 0;
- char *constraint, *orig_constraint;
+ const char *constraint, *orig_constraint;
int c_len;
rtx op;
return;
}
- c_len = strlen (TREE_STRING_POINTER (TREE_PURPOSE (tail)));
constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+ c_len = strlen (constraint);
orig_constraint = constraint;
/* Make sure constraint has neither `=', `+', nor '&'. */
break;
case '<': case '>':
- case '?': case '!': case '*':
+ case '?': case '!': case '*': case '#':
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L': case 'M':
for (j = constraint[j] - '0'; j > 0; --j)
o = TREE_CHAIN (o);
- c_len = strlen (TREE_STRING_POINTER (TREE_PURPOSE (o)));
constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
+ c_len = strlen (constraint);
j = 0;
break;
}
|| GET_CODE (op) == CONCAT)
{
tree type = TREE_TYPE (TREE_VALUE (tail));
- rtx memloc = assign_temp (type, 1, 1, 1);
+ tree qual_type = build_qualified_type (type,
+ (TYPE_QUALS (type)
+ | TYPE_QUAL_CONST));
+ rtx memloc = assign_temp (qual_type, 1, 1, 1);
emit_move_insn (memloc, op);
op = memloc;
ASM_OPERANDS_INPUT (body, ninputs - ninout + i)
= output_rtx[j];
ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, ninputs - ninout + i)
- = gen_rtx_ASM_INPUT (inout_mode[i], digit_strings[j]);
+ = gen_rtx_ASM_INPUT (inout_mode[i], digit_string (j));
}
generating_concat_p = old_generating_concat_p;
except inside a ({...}) where they may be useful. */
if (expr_stmts_for_value == 0 && exp != error_mark_node)
{
- if (! TREE_SIDE_EFFECTS (exp)
- && (extra_warnings || warn_unused_value)
- && !(TREE_CODE (exp) == CONVERT_EXPR
- && VOID_TYPE_P (TREE_TYPE (exp))))
- warning_with_file_and_line (emit_filename, emit_lineno,
- "statement with no effect");
+ if (! TREE_SIDE_EFFECTS (exp))
+ {
+ if ((extra_warnings || warn_unused_value)
+ && !(TREE_CODE (exp) == CONVERT_EXPR
+ && VOID_TYPE_P (TREE_TYPE (exp))))
+ warning_with_file_and_line (emit_filename, emit_lineno,
+ "statement with no effect");
+ }
else if (warn_unused_value)
warn_if_unused_value (exp);
}
if (TREE_USED (exp))
return 0;
+ /* Don't warn about void constructs. This includes casting to void,
+ void function calls, and statement expressions with a final cast
+ to void. */
+ if (VOID_TYPE_P (TREE_TYPE (exp)))
+ return 0;
+
+ /* If this is an expression with side effects, don't warn. */
+ if (TREE_SIDE_EFFECTS (exp))
+ return 0;
+
switch (TREE_CODE (exp))
{
case PREINCREMENT_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
case EXIT_EXPR:
- /* We don't warn about COND_EXPR because it may be a useful
- construct if either arm contains a side effect. */
- case COND_EXPR:
return 0;
case BIND_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
- /* Don't warn about values cast to void. */
- if (VOID_TYPE_P (TREE_TYPE (exp)))
- return 0;
/* Don't warn about conversions not explicit in the user's program. */
if (TREE_NO_UNUSED_WARNING (exp))
return 0;
tree
expand_start_stmt_expr ()
{
- int momentary;
tree t;
/* Make the RTL_EXPR node temporary, not momentary,
so that rtl_expr_chain doesn't become garbage. */
- momentary = suspend_momentary ();
t = make_node (RTL_EXPR);
- resume_momentary (momentary);
do_pending_stack_adjust ();
start_sequence_for_rtl_expr (t);
NO_DEFER_POP;
return thisloop;
}
+/* Begin a null, aka do { } while (0) "loop". But since the contents
+ of said loop can still contain a break, we must frob the loop nest. */
+
+struct nesting *
+expand_start_null_loop ()
+{
+ register struct nesting *thisloop = ALLOC_NESTING ();
+
+ /* Make an entry on loop_stack for the loop we are entering. */
+
+ thisloop->next = loop_stack;
+ thisloop->all = nesting_stack;
+ thisloop->depth = ++nesting_depth;
+ thisloop->data.loop.start_label = emit_note (NULL, NOTE_INSN_DELETED);
+ thisloop->data.loop.end_label = gen_label_rtx ();
+ thisloop->data.loop.alt_end_label = NULL_RTX;
+ thisloop->data.loop.continue_label = thisloop->data.loop.end_label;
+ thisloop->exit_label = thisloop->data.loop.end_label;
+ loop_stack = thisloop;
+ nesting_stack = thisloop;
+
+ return thisloop;
+}
+
/* Specify the continuation point for a loop started with
expand_start_loop_continue_elsewhere.
Use this at the point in the code to which a continue statement
last_expr_type = 0;
}
+/* Finish a null loop, aka do { } while (0). */
+
+void
+expand_end_null_loop ()
+{
+ do_pending_stack_adjust ();
+ emit_label (loop_stack->data.loop.end_label);
+
+ POPSTACK (loop_stack);
+
+ last_expr_type = 0;
+}
+
/* Generate a jump to the current loop's continue-point.
This is usually the top of the loop, but may be specified
explicitly elsewhere. If not currently inside a loop,
#endif
if (retval == error_mark_node)
- retval_rhs = NULL_TREE;
+ {
+ /* Treat this like a return of no value from a function that
+ returns a value. */
+ expand_null_return ();
+ return;
+ }
else if (TREE_CODE (retval) == RESULT_DECL)
retval_rhs = retval;
else if ((TREE_CODE (retval) == MODIFY_EXPR || TREE_CODE (retval) == INIT_EXPR)
rtx result_val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
enum machine_mode tmpmode, result_reg_mode;
+ if (bytes == 0)
+ {
+ expand_null_return ();
+ return;
+ }
+
/* Structures whose size is not a multiple of a word are aligned
to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
machine, this means we must skip the empty high order bytes when
/* Find the smallest integer mode large enough to hold the
entire structure and use that mode instead of BLKmode
on the USE insn for the return register. */
- bytes = int_size_in_bytes (TREE_TYPE (retval_rhs));
for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmpmode != VOIDmode;
tmpmode = GET_MODE_WIDER_MODE (tmpmode))
- {
- /* Have we found a large enough mode? */
- if (GET_MODE_SIZE (tmpmode) >= bytes)
- break;
- }
+ /* Have we found a large enough mode? */
+ if (GET_MODE_SIZE (tmpmode) >= bytes)
+ break;
/* No suitable mode found. */
if (tmpmode == VOIDmode)
{
/* Calculate the return value into a temporary (usually a pseudo
reg). */
- val = assign_temp (TREE_TYPE (DECL_RESULT (current_function_decl)),
- 0, 0, 1);
+ tree ot = TREE_TYPE (DECL_RESULT (current_function_decl));
+ tree nt = build_qualified_type (ot, TYPE_QUALS (ot) | TYPE_QUAL_CONST);
+
+ val = assign_temp (nt, 0, 0, 1);
val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val);
emit_queue ();
if (type == error_mark_node)
DECL_RTL (decl) = gen_rtx_MEM (BLKmode, const0_rtx);
+
else if (DECL_SIZE (decl) == 0)
/* Variable with incomplete type. */
{
if (DECL_INITIAL (decl) == 0)
/* Error message was already done; now avoid a crash. */
- DECL_RTL (decl) = assign_stack_temp (DECL_MODE (decl), 0, 1);
+ DECL_RTL (decl) = gen_rtx_MEM (BLKmode, const0_rtx);
else
/* An initializer is going to decide the size of this array.
Until we know the size, represent its address with a reg. */
&& !(flag_float_store
&& TREE_CODE (type) == REAL_TYPE)
&& ! TREE_THIS_VOLATILE (decl)
- && ! TREE_ADDRESSABLE (decl)
&& (DECL_REGISTER (decl) || optimize)
/* if -fcheck-memory-usage, check all variables. */
&& ! current_function_check_memory_usage)
TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
maybe_set_unchanging (DECL_RTL (decl), decl);
+
+ /* If something wants our address, try to use ADDRESSOF. */
+ if (TREE_ADDRESSABLE (decl))
+ put_var_into_stack (decl);
}
else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
emit_move_insn (flag, const1_rtx);
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
cond = build_decl (VAR_DECL, NULL_TREE, type_for_mode (word_mode, 1));
DECL_RTL (cond) = flag;
cleanup, integer_zero_node);
cleanup = fold (cleanup);
- pop_obstacks ();
-
cleanups = thisblock->data.block.cleanup_ptr;
}
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
cleanup = unsave_expr (cleanup);
- pop_obstacks ();
- t = *cleanups = temp_tree_cons (decl, cleanup, *cleanups);
+ t = *cleanups = tree_cons (decl, cleanup, *cleanups);
if (! cond_context)
/* If this block has a cleanup, it belongs in stack_block_stack. */
/* Record the cleanup for the dynamic handler chain. */
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
cleanup = make_node (POPDCC_EXPR);
- pop_obstacks ();
/* Add the cleanup in a manner similar to expand_decl_cleanup. */
thisblock->data.block.cleanups
- = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
+ = tree_cons (decl, cleanup, thisblock->data.block.cleanups);
/* If this block has a cleanup, it belongs in stack_block_stack. */
stack_block_stack = thisblock;
/* Record the cleanup for the dynamic handler chain. */
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
cleanup = make_node (POPDHC_EXPR);
- pop_obstacks ();
/* Add the cleanup in a manner similar to expand_decl_cleanup. */
thisblock->data.block.cleanups
- = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
+ = tree_cons (decl, cleanup, thisblock->data.block.cleanups);
/* If this block has a cleanup, it belongs in stack_block_stack. */
stack_block_stack = thisblock;
if (cleanup != 0)
thisblock->data.block.cleanups
- = temp_tree_cons (decl_elt, cleanup_elt,
- thisblock->data.block.cleanups);
+ = tree_cons (decl_elt, cleanup_elt,
+ thisblock->data.block.cleanups);
}
}
\f
}
}
- /* Add this label to the chain, and succeed.
- Copy LOW, HIGH so they are on temporary rather than momentary
- obstack and will thus survive till the end of the case statement. */
+ /* Add this label to the chain, and succeed. */
- r = (struct case_node *) oballoc (sizeof (struct case_node));
- r->low = copy_node (low);
+ r = (struct case_node *) xmalloc (sizeof (struct case_node));
+ r->low = low;
/* If the bounds are equal, turn this into the one-value case. */
if (tree_int_cst_equal (low, high))
r->high = r->low;
else
- r->high = copy_node (high);
+ r->high = high;
r->code_label = label;
expand_label (label);
/* We deliberately use calloc here, not cmalloc, so that we can suppress
this optimization if we don't have enough memory rather than
aborting, as xmalloc would do. */
- && (cases_seen = (unsigned char *) calloc (bytes_needed, 1)) != NULL)
+ && (cases_seen =
+ (unsigned char *) really_call_calloc (bytes_needed, 1)) != NULL)
{
HOST_WIDE_INT i;
tree v = TYPE_VALUES (type);
#endif /* 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
in which ORIG_INDEX is the expression to be tested.
ncases = TREE_INT_CST_LOW (range) + 1;
labelvec = (rtx *) alloca (ncases * sizeof (rtx));
- bzero ((char *) labelvec, ncases * sizeof (rtx));
+ memset ((char *) labelvec, 0, ncases * sizeof (rtx));
for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
{
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 ();
estimate_case_costs (node)
case_node_ptr node;
{
- tree min_ascii = build_int_2 (-1, -1);
+ tree min_ascii = integer_minus_one_node;
tree max_ascii = convert (TREE_TYPE (node->high), build_int_2 (127, 0));
case_node_ptr n;
int i;
/* If we haven't already made the cost table, make it now. Note that the
lower bound of the table is -1, not zero. */
- if (cost_table == NULL)
+ if (! cost_table_initialized)
{
- cost_table = cost_table_ + 1;
+ cost_table_initialized = 1;
for (i = 0; i < 128; i++)
{
if (ISALNUM (i))
- cost_table[i] = 16;
+ COST_TABLE (i) = 16;
else if (ISPUNCT (i))
- cost_table[i] = 8;
+ COST_TABLE (i) = 8;
else if (ISCNTRL (i))
- cost_table[i] = -1;
+ COST_TABLE (i) = -1;
}
- cost_table[' '] = 8;
- cost_table['\t'] = 4;
- cost_table['\0'] = 4;
- cost_table['\n'] = 2;
- cost_table['\f'] = 1;
- cost_table['\v'] = 1;
- cost_table['\b'] = 1;
+ COST_TABLE (' ') = 8;
+ COST_TABLE ('\t') = 4;
+ COST_TABLE ('\0') = 4;
+ COST_TABLE ('\n') = 2;
+ COST_TABLE ('\f') = 1;
+ COST_TABLE ('\v') = 1;
+ COST_TABLE ('\b') = 1;
}
/* See if all the case expressions look like text. It is text if the
for (i = (HOST_WIDE_INT) TREE_INT_CST_LOW (n->low);
i <= (HOST_WIDE_INT) TREE_INT_CST_LOW (n->high); i++)
- if (cost_table[i] < 0)
+ if (COST_TABLE (i) < 0)
return 0;
}
{
ranges++;
if (use_cost_table)
- cost += cost_table[TREE_INT_CST_LOW (np->high)];
+ cost += COST_TABLE (TREE_INT_CST_LOW (np->high));
}
if (use_cost_table)
- cost += cost_table[TREE_INT_CST_LOW (np->low)];
+ cost += COST_TABLE (TREE_INT_CST_LOW (np->low));
i++;
np = np->right;
{
/* Skip nodes while their cost does not reach that amount. */
if (!tree_int_cst_equal ((*npp)->low, (*npp)->high))
- i -= cost_table[TREE_INT_CST_LOW ((*npp)->high)];
- i -= cost_table[TREE_INT_CST_LOW ((*npp)->low)];
+ i -= COST_TABLE (TREE_INT_CST_LOW ((*npp)->high));
+ i -= COST_TABLE (TREE_INT_CST_LOW ((*npp)->low));
if (i <= 0)
break;
npp = &(*npp)->right;
a branch-greater-than will get us to the default
label correctly. */
if (use_cost_table
- && cost_table[TREE_INT_CST_LOW (node->high)] < 12)
+ && COST_TABLE (TREE_INT_CST_LOW (node->high)) < 12)
;
#endif /* 0 */
if (node->left->left || node->left->right