static void tree_make_forwarder_block (edge);
static void tree_cfg2vcg (FILE *);
static inline void change_bb_for_stmt (tree t, basic_block bb);
+static bool computed_goto_p (const_tree);
/* Flowgraph optimization and cleanup. */
static void tree_merge_blocks (basic_block, basic_block);
tree labels = SWITCH_LABELS (stmt);
int old_size = TREE_VEC_LENGTH (labels);
int i, j, new_size = old_size;
- tree default_case = TREE_VEC_ELT (labels, old_size - 1);
- tree default_label;
+ tree default_case = NULL_TREE;
+ tree default_label = NULL_TREE;
/* The default label is always the last case in a switch
- statement after gimplification. */
- default_label = CASE_LABEL (default_case);
+ statement after gimplification if it was not optimized
+ away. */
+ if (!CASE_LOW (TREE_VEC_ELT (labels, old_size - 1))
+ && !CASE_HIGH (TREE_VEC_ELT (labels, old_size - 1)))
+ {
+ default_case = TREE_VEC_ELT (labels, old_size - 1);
+ default_label = CASE_LABEL (default_case);
+ old_size--;
+ }
- /* Look for possible opportunities to merge cases.
- Ignore the last element of the label vector because it
- must be the default case. */
+ /* Look for possible opportunities to merge cases. */
i = 0;
- while (i < old_size - 1)
+ while (i < old_size)
{
tree base_case, base_label, base_high;
base_case = TREE_VEC_ELT (labels, i);
/* Try to merge case labels. Break out when we reach the end
of the label vector or when we cannot merge the next case
label with the current one. */
- while (i < old_size - 1)
+ while (i < old_size)
{
tree merge_case = TREE_VEC_ELT (labels, i);
tree merge_label = CASE_LABEL (merge_case);
update_call_expr_flags (tree call)
{
tree decl = get_callee_fndecl (call);
+ int flags;
if (!decl)
return;
- if (call_expr_flags (call) & (ECF_CONST | ECF_PURE))
+ flags = call_expr_flags (call);
+ if (flags & (ECF_CONST | ECF_PURE) && !(flags & ECF_LOOPING_CONST_OR_PURE))
TREE_SIDE_EFFECTS (call) = 0;
if (TREE_NOTHROW (decl))
TREE_NOTHROW (call) = 1;
int flags = call_expr_flags (t);
if (flags & ECF_MAY_BE_ALLOCA)
- current_function_calls_alloca = true;
+ cfun->calls_alloca = true;
if (flags & ECF_RETURNS_TWICE)
- current_function_calls_setjmp = true;
+ cfun->calls_setjmp = true;
}
void
clear_special_calls (void)
{
- current_function_calls_alloca = false;
- current_function_calls_setjmp = false;
+ cfun->calls_alloca = false;
+ cfun->calls_setjmp = false;
}
data->last_goto = NULL;
break;
+ case OMP_PARALLEL:
+ /* Make sure the outermost BIND_EXPR in OMP_BODY isn't removed
+ as useless. */
+ remove_useless_stmts_1 (&BIND_EXPR_BODY (OMP_BODY (*tp)), data);
+ data->last_goto = NULL;
+ break;
+
+ case OMP_SECTIONS:
+ case OMP_SINGLE:
+ case OMP_SECTION:
+ case OMP_MASTER :
+ case OMP_ORDERED:
+ case OMP_CRITICAL:
+ remove_useless_stmts_1 (&OMP_BODY (*tp), data);
+ data->last_goto = NULL;
+ break;
+
+ case OMP_FOR:
+ remove_useless_stmts_1 (&OMP_FOR_BODY (*tp), data);
+ data->last_goto = NULL;
+ if (OMP_FOR_PRE_BODY (*tp))
+ {
+ remove_useless_stmts_1 (&OMP_FOR_PRE_BODY (*tp), data);
+ data->last_goto = NULL;
+ }
+ break;
+
default:
data->last_goto = NULL;
break;
{
/* A non-pure/const CALL_EXPR alters flow control if the current
function has nonlocal labels. */
- if (TREE_SIDE_EFFECTS (call) && current_function_has_nonlocal_label)
+ if (TREE_SIDE_EFFECTS (call) && cfun->has_nonlocal_label)
return true;
/* A CALL_EXPR also alters control flow if it does not return. */
/* Return true if T is a computed goto. */
-bool
+static bool
computed_goto_p (const_tree t)
{
return (TREE_CODE (t) == GOTO_EXPR
if (TREE_CODE (t) == WITH_SIZE_EXPR)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CALL_EXPR)
- return TREE_SIDE_EFFECTS (t) && current_function_has_nonlocal_label;
+ return TREE_SIDE_EFFECTS (t) && cfun->has_nonlocal_label;
return false;
}
if (uid == -1)
{
unsigned old_len = VEC_length (basic_block, label_to_block_map);
- LABEL_DECL_UID (t) = uid = cfun->last_label_uid++;
+ LABEL_DECL_UID (t) = uid = cfun->cfg->last_label_uid++;
if (old_len <= (unsigned) uid)
{
unsigned new_len = 3 * uid / 2;
verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
tree t = *tp, x;
- bool in_phi = (data != NULL);
if (TYPE_P (t))
*walk_subtrees = 0;
case ADDR_EXPR:
{
- bool old_invariant;
bool old_constant;
bool old_side_effects;
- bool new_invariant;
bool new_constant;
bool new_side_effects;
- /* ??? tree-ssa-alias.c may have overlooked dead PHI nodes, missing
- dead PHIs that take the address of something. But if the PHI
- result is dead, the fact that it takes the address of anything
- is irrelevant. Because we can not tell from here if a PHI result
- is dead, we just skip this check for PHIs altogether. This means
- we may be missing "valid" checks, but what can you do?
- This was PR19217. */
- if (in_phi)
- break;
+ gcc_assert (is_gimple_address (t));
- old_invariant = TREE_INVARIANT (t);
old_constant = TREE_CONSTANT (t);
old_side_effects = TREE_SIDE_EFFECTS (t);
recompute_tree_invariant_for_addr_expr (t);
- new_invariant = TREE_INVARIANT (t);
new_side_effects = TREE_SIDE_EFFECTS (t);
new_constant = TREE_CONSTANT (t);
- if (old_invariant != new_invariant)
- {
- error ("invariant not recomputed when ADDR_EXPR changed");
- return t;
- }
-
if (old_constant != new_constant)
{
error ("constant not recomputed when ADDR_EXPR changed");
return x;
}
- /* Stop recursing and verifying invariant ADDR_EXPRs, they tend
- to become arbitrary complicated. */
- if (is_gimple_min_invariant (t))
- *walk_subtrees = 0;
break;
}
}
break;
- case NOP_EXPR:
- case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ gcc_unreachable ();
+
+ CASE_CONVERT:
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
case NEGATE_EXPR:
case ABS_EXPR:
case BIT_NOT_EXPR:
- case NON_LVALUE_EXPR:
case TRUTH_NOT_EXPR:
CHECK_OP (0, "invalid operand to unary operator");
break;
return false;
}
+/* Return true if TYPE1 is a fixed-point type and if conversions to and
+ from TYPE2 can be handled by FIXED_CONVERT_EXPR. */
+
+static bool
+valid_fixed_convert_types_p (tree type1, tree type2)
+{
+ return (FIXED_POINT_TYPE_P (type1)
+ && (INTEGRAL_TYPE_P (type2)
+ || SCALAR_FLOAT_TYPE_P (type2)
+ || FIXED_POINT_TYPE_P (type2)));
+}
+
/* Verify the GIMPLE expression EXPR. Returns true if there is an
error, otherwise false. */
/* Special codes we cannot handle via their class. */
switch (TREE_CODE (expr))
{
- case NOP_EXPR:
- case CONVERT_EXPR:
+ CASE_CONVERT:
{
tree op = TREE_OPERAND (expr, 0);
if (!is_gimple_val (op))
return false;
}
+ case FIXED_CONVERT_EXPR:
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in conversion");
+ return true;
+ }
+
+ if (!valid_fixed_convert_types_p (type, TREE_TYPE (op))
+ && !valid_fixed_convert_types_p (TREE_TYPE (op), type))
+ {
+ error ("invalid types in fixed-point conversion");
+ debug_generic_expr (type);
+ debug_generic_expr (TREE_TYPE (op));
+ return true;
+ }
+
+ return false;
+ }
+
case FLOAT_EXPR:
{
tree op = TREE_OPERAND (expr, 0);
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
+ gcc_unreachable ();
+
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
case CALL_EXPR:
/* FIXME. The C frontend passes unpromoted arguments in case it
didn't see a function declaration before the call. */
- return false;
+ {
+ tree decl = CALL_EXPR_FN (expr);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_LOOPING_CONST_OR_PURE_P (decl)
+ && (!DECL_PURE_P (decl))
+ && (!TREE_READONLY (decl)))
+ {
+ error ("invalid pure const state for function");
+ return true;
+ }
+ return false;
+ }
case OBJ_TYPE_REF:
/* FIXME. */
if (addr)
{
debug_generic_stmt (addr);
+ if (addr != stmt)
+ {
+ inform ("in statement");
+ debug_generic_stmt (stmt);
+ }
return true;
}
are not considered gimple values. */
else if (TREE_CODE (t) != SSA_NAME
&& TREE_CODE (t) != FUNCTION_DECL
- && !is_gimple_val (t))
+ && !is_gimple_min_invariant (t))
{
error ("PHI def is not a GIMPLE value");
debug_generic_stmt (phi);
err |= true;
}
- addr = walk_tree (&t, verify_expr, (void *) 1, NULL);
- if (addr)
- {
- debug_generic_stmt (addr);
- err |= true;
- }
-
addr = walk_tree (&t, verify_node_sharing, visited, NULL);
if (addr)
{
/* Verify that the case labels are sorted. */
prev = TREE_VEC_ELT (vec, 0);
- for (i = 1; i < n - 1; ++i)
+ for (i = 1; i < n; ++i)
{
tree c = TREE_VEC_ELT (vec, i);
if (! CASE_LOW (c))
{
- error ("found default case not at end of case vector");
- err = 1;
+ if (i != n - 1)
+ {
+ error ("found default case not at end of case vector");
+ err = 1;
+ }
continue;
}
if (! tree_int_cst_lt (CASE_LOW (prev), CASE_LOW (c)))
}
prev = c;
}
- if (CASE_LOW (TREE_VEC_ELT (vec, n - 1)))
- {
- error ("no default case found at end of case vector");
- err = 1;
- }
+ /* VRP will remove the default case if it can prove it will
+ never be executed. So do not verify there always exists
+ a default case here. */
FOR_EACH_EDGE (e, ei, bb->succs)
{
adding blocks when the dominator traversal reaches EXIT. This
function silently assumes that ENTRY strictly dominates EXIT. */
-static void
+void
gather_blocks_in_sese_region (basic_block entry, basic_block exit,
VEC(basic_block,heap) **bbs_p)
{
if (SSA_VAR_P (t))
{
new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t));
- f->unexpanded_var_list
- = tree_cons (NULL_TREE, new_t, f->unexpanded_var_list);
+ f->local_decls = tree_cons (NULL_TREE, new_t, f->local_decls);
}
else
{
gcc_assert (DECL_CONTEXT (label) == dest_cfun->decl);
- if (uid >= dest_cfun->last_label_uid)
- dest_cfun->last_label_uid = uid + 1;
+ if (uid >= dest_cfun->cfg->last_label_uid)
+ dest_cfun->cfg->last_label_uid = uid + 1;
}
else if (TREE_CODE (stmt) == RESX_EXPR && eh_offset != 0)
TREE_OPERAND (stmt, 0) =
m->base.from = decl;
m->to = create_artificial_label ();
LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
- if (LABEL_DECL_UID (m->to) >= cfun->last_label_uid)
- cfun->last_label_uid = LABEL_DECL_UID (m->to) + 1;
+ if (LABEL_DECL_UID (m->to) >= cfun->cfg->last_label_uid)
+ cfun->cfg->last_label_uid = LABEL_DECL_UID (m->to) + 1;
slot = htab_find_slot_with_hash (hash, m, m->hash, INSERT);
gcc_assert (*slot == NULL);
arg = DECL_ARGUMENTS (fn);
while (arg)
{
+ print_generic_expr (file, TREE_TYPE (arg), dump_flags);
+ fprintf (file, " ");
print_generic_expr (file, arg, dump_flags);
+ if (flags & TDF_VERBOSE)
+ print_node (file, "", arg, 4);
if (TREE_CHAIN (arg))
fprintf (file, ", ");
arg = TREE_CHAIN (arg);
}
fprintf (file, ")\n");
+ if (flags & TDF_VERBOSE)
+ print_node (file, "", fn, 2);
+
dsf = DECL_STRUCT_FUNCTION (fn);
if (dsf && (flags & TDF_DETAILS))
dump_eh_tree (file, dsf);
/* When GIMPLE is lowered, the variables are no longer available in
BIND_EXPRs, so display them separately. */
- if (cfun && cfun->decl == fn && cfun->unexpanded_var_list)
+ if (cfun && cfun->decl == fn && cfun->local_decls)
{
ignore_topmost_bind = true;
fprintf (file, "{\n");
- for (vars = cfun->unexpanded_var_list; vars; vars = TREE_CHAIN (vars))
+ for (vars = cfun->local_decls; vars; vars = TREE_CHAIN (vars))
{
var = TREE_VALUE (vars);
print_generic_decl (file, var, flags);
+ if (flags & TDF_VERBOSE)
+ print_node (file, "", var, 4);
fprintf (file, "\n");
any_var = true;
static bool
need_fake_edge_p (tree t)
{
- tree call;
+ tree call, fndecl = NULL_TREE;
+ int call_flags;
/* NORETURN and LONGJMP calls already have an edge to exit.
CONST and PURE calls do not need one.
the counter incrementation code from -fprofile-arcs
leads to different results from -fbranch-probabilities. */
call = get_call_expr_in (t);
- if (call
- && !(call_expr_flags (call) & ECF_NORETURN))
+ if (call)
+ {
+ fndecl = get_callee_fndecl (call);
+ call_flags = call_expr_flags (call);
+ }
+
+ if (call && fndecl && DECL_BUILT_IN (fndecl)
+ && (call_flags & ECF_NOTHROW)
+ && !(call_flags & ECF_NORETURN)
+ && !(call_flags & ECF_RETURNS_TWICE))
+ return false;
+
+ if (call && !(call_flags & ECF_NORETURN))
return true;
if (TREE_CODE (t) == ASM_EXPR
{
bool changed = tree_purge_dead_eh_edges (bb);
- if (current_function_has_nonlocal_label)
+ if (cfun->has_nonlocal_label)
{
tree stmt = last_stmt (bb);
edge_iterator ei;
if (warn_missing_noreturn
&& !TREE_THIS_VOLATILE (cfun->decl)
&& EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
- && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl))
+ && !lang_hooks.missing_noreturn_ok_p (cfun->decl))
warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
"for attribute %<noreturn%>",
cfun->decl);