if (simple_goto_p (goto_t))
{
edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+#ifdef USE_MAPPED_LOCATION
+ e->goto_locus = EXPR_LOCATION (goto_t);
+#else
e->goto_locus = EXPR_LOCUS (goto_t);
+#endif
bsi_remove (&last);
return;
}
tree labels = SWITCH_LABELS (stmt);
int old_size = TREE_VEC_LENGTH (labels);
int i, j, new_size = old_size;
+ tree default_label = TREE_VEC_ELT (labels, old_size - 1);
/* Look for possible opportunities to merge cases.
Ignore the last element of the label vector because it
if (! base_case)
abort ();
- type = TREE_TYPE (CASE_LOW (base_case));
base_label = CASE_LABEL (base_case);
+
+ /* Discard cases that have the same destination as the
+ default case. */
+ if (base_label == default_label)
+ {
+ TREE_VEC_ELT (labels, i) = NULL_TREE;
+ i++;
+ continue;
+ }
+
+ type = TREE_TYPE (CASE_LOW (base_case));
base_high = CASE_HIGH (base_case) ?
CASE_HIGH (base_case) : CASE_LOW (base_case);
static bool
remove_useless_stmts_warn_notreached (tree stmt)
{
- if (EXPR_LOCUS (stmt))
+ if (EXPR_HAS_LOCATION (stmt))
{
- warning ("%Hwill never be executed", EXPR_LOCUS (stmt));
+ location_t loc = EXPR_LOCATION (stmt);
+ warning ("%Hwill never be executed", &loc);
return true;
}
remove_bb (basic_block bb)
{
block_stmt_iterator i;
- location_t *loc = NULL;
+ source_locus loc = 0;
if (dump_file)
{
jump threading, thus resulting in bogus warnings. Not great,
since this way we lose warnings for gotos in the original
program that are indeed unreachable. */
- if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_LOCUS (stmt) && !loc)
+ if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_HAS_LOCATION (stmt) && !loc)
+#ifdef USE_MAPPED_LOCATION
+ loc = EXPR_LOCATION (stmt);
+#else
loc = EXPR_LOCUS (stmt);
+#endif
}
/* If requested, give a warning that the first statement in the
loop above, so the last statement we process is the first statement
in the block. */
if (warn_notreached && loc)
+#ifdef USE_MAPPED_LOCATION
+ warning ("%Hwill never be executed", &loc);
+#else
warning ("%Hwill never be executed", loc);
+#endif
remove_phi_nodes_and_edges_for_unreachable_block (bb);
}
basic_block bb;
block_stmt_iterator last;
edge e;
- tree stmt, label, forward;
+ tree stmt, label;
FOR_EACH_BB (bb)
{
label = tree_block_label (e->dest);
- /* If this is a goto to a goto, jump to the final destination.
- Handles unfactoring of the computed jumps.
- ??? Why bother putting this back together when rtl is just
- about to take it apart again? */
- forward = last_and_only_stmt (e->dest);
- if (forward
- && TREE_CODE (forward) == GOTO_EXPR)
- label = GOTO_DESTINATION (forward);
-
stmt = build1 (GOTO_EXPR, void_type_node, label);
+#ifdef USE_MAPPED_LOCATION
+ SET_EXPR_LOCATION (stmt, e->goto_locus);
+#else
SET_EXPR_LOCUS (stmt, e->goto_locus);
+#endif
bsi_insert_after (&last, stmt, BSI_NEW_STMT);
e->flags &= ~EDGE_FALLTHRU;
}
properly noticed as such. */
static tree
-verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
+verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
tree t = *tp, x;
if (TYPE_P (t))
*walk_subtrees = 0;
+
+ /* Check operand N for being valid GIMPLE and give error MSG if not.
+ We check for constants explicitly since they are not considered
+ gimple invariants if they overflowed. */
+#define CHECK_OP(N, MSG) \
+ do { if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, N))) != 'c' \
+ && !is_gimple_val (TREE_OPERAND (t, N))) \
+ { error (MSG); return TREE_OPERAND (t, N); }} while (0)
switch (TREE_CODE (t))
{
&& is_gimple_reg (TREE_OPERAND (x, 0)))
{
error ("GIMPLE register modified with BIT_FIELD_REF");
- return *tp;
+ return t;
}
break;
case ADDR_EXPR:
- x = TREE_OPERAND (t, 0);
- while (TREE_CODE (x) == ARRAY_REF
- || TREE_CODE (x) == COMPONENT_REF
- || TREE_CODE (x) == REALPART_EXPR
- || TREE_CODE (x) == IMAGPART_EXPR)
- x = TREE_OPERAND (x, 0);
+ /* Skip any references (they will be checked when we recurse down the
+ tree) and ensure that any variable used as a prefix is marked
+ addressable. */
+ for (x = TREE_OPERAND (t, 0);
+ (handled_component_p (x)
+ || TREE_CODE (x) == REALPART_EXPR
+ || TREE_CODE (x) == IMAGPART_EXPR);
+ x = TREE_OPERAND (x, 0))
+ ;
+
if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
return NULL;
if (!TREE_ADDRESSABLE (x))
case BIT_NOT_EXPR:
case NON_LVALUE_EXPR:
case TRUTH_NOT_EXPR:
- x = TREE_OPERAND (t, 0);
- /* We check for constants explicitly since they are not considered
- gimple invariants if they overflowed. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
- && !is_gimple_val (x))
- {
- error ("Invalid operand to unary operator");
- return x;
- }
+ CHECK_OP (0, "Invalid operand to unary operator");
break;
case REALPART_EXPR:
case IMAGPART_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ case BIT_FIELD_REF:
+ case VIEW_CONVERT_EXPR:
+ /* We have a nest of references. Verify that each of the operands
+ that determine where to reference is either a constant or a variable,
+ verify that the base is valid, and then show we've already checked
+ the subtrees. */
+ while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR
+ || handled_component_p (t))
+ {
+ if (TREE_CODE (t) == COMPONENT_REF && TREE_OPERAND (t, 2))
+ CHECK_OP (2, "Invalid COMPONENT_REF offset operator");
+ else if (TREE_CODE (t) == ARRAY_REF
+ || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ CHECK_OP (1, "Invalid array index.");
+ if (TREE_OPERAND (t, 2))
+ CHECK_OP (2, "Invalid array lower bound.");
+ if (TREE_OPERAND (t, 3))
+ CHECK_OP (3, "Invalid array stride.");
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ CHECK_OP (1, "Invalid operand to BIT_FIELD_REF");
+ CHECK_OP (2, "Invalid operand to BIT_FIELD_REF");
+ }
+
+ t = TREE_OPERAND (t, 0);
+ }
+
+ if (TREE_CODE_CLASS (TREE_CODE (t)) != 'c'
+ && !is_gimple_lvalue (t))
+ {
+ error ("Invalid reference prefix.");
+ return t;
+ }
+ *walk_subtrees = 0;
break;
case LT_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
- x = TREE_OPERAND (t, 0);
- /* We check for constants explicitly since they are not considered
- gimple invariants if they overflowed. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
- && !is_gimple_val (x))
- {
- error ("Invalid operand to binary operator");
- return x;
- }
- x = TREE_OPERAND (t, 1);
- /* We check for constants explicitly since they are not considered
- gimple invariants if they overflowed. */
- if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
- && !is_gimple_val (x))
- {
- error ("Invalid operand to binary operator");
- return x;
- }
+ CHECK_OP (0, "Invalid operand to binary operator");
+ CHECK_OP (1, "Invalid operand to binary operator");
break;
default:
break;
}
return NULL;
+
+#undef CHECK_OP
}
TODO: Implement type checking. */
static bool
-verify_stmt (tree stmt)
+verify_stmt (tree stmt, bool last_in_block)
{
tree addr;
if (!is_gimple_stmt (stmt))
{
error ("Is not a valid GIMPLE statement.");
- debug_generic_stmt (stmt);
- return true;
+ goto fail;
}
addr = walk_tree (&stmt, verify_expr, NULL, NULL);
return true;
}
+ /* If the statement is marked as part of an EH region, then it is
+ expected that the statement could throw. Verify that when we
+ have optimizations that simplify statements such that we prove
+ that they cannot throw, that we update other data structures
+ to match. */
+ if (lookup_stmt_eh_region (stmt) >= 0)
+ {
+ if (!tree_could_throw_p (stmt))
+ {
+ error ("Statement marked for throw, but doesn't.");
+ goto fail;
+ }
+ if (!last_in_block && tree_can_throw_internal (stmt))
+ {
+ error ("Statement marked for throw in middle of block.");
+ goto fail;
+ }
+ }
+
return false;
+
+ fail:
+ debug_generic_stmt (stmt);
+ return true;
}
|| TREE_CODE (t) == SSA_NAME)
return true;
- while ((TREE_CODE (t) == ARRAY_REF
+ while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
/* We check for constants explicitly since they are not considered
gimple invariants if they overflowed. */
&& (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c'
}
}
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
{
tree stmt = bsi_stmt (bsi);
- err |= verify_stmt (stmt);
+ bsi_next (&bsi);
+ err |= verify_stmt (stmt, bsi_end_p (bsi));
addr = walk_tree (&stmt, verify_node_sharing, htab, NULL);
if (addr)
{
dest = dest->succ->dest)
{
/* An infinite loop detected. We redirect the edge anyway, so
- that the loop is shrinked into single basic block. */
+ that the loop is shrunk into single basic block. */
if (!bb_ann (dest)->forwardable)
break;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
+ tree copy;
if (TREE_CODE (stmt) == LABEL_EXPR)
continue;
- bsi_insert_after (&bsi_tgt, unshare_expr (stmt), BSI_NEW_STMT);
+ copy = unshare_expr (stmt);
+
+ /* Copy also the virtual operands. */
+ get_stmt_ann (copy);
+ copy_virtual_operands (copy, stmt);
+
+ bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT);
}
return new_bb;
return blocks_split;
}
+bool
+tree_purge_dead_eh_edges (basic_block bb)
+{
+ bool changed = false;
+ edge e, next;
+ tree stmt = last_stmt (bb);
+
+ if (stmt && tree_can_throw_internal (stmt))
+ return false;
+
+ for (e = bb->succ; e ; e = next)
+ {
+ next = e->succ_next;
+ if (e->flags & EDGE_EH)
+ {
+ ssa_remove_edge (e);
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+bool
+tree_purge_all_dead_eh_edges (bitmap blocks)
+{
+ bool changed = false;
+ size_t i;
+
+ EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i,
+ { changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i)); });
+
+ return changed;
+}
struct cfg_hooks tree_cfg_hooks = {
"tree",
static void
execute_warn_function_return (void)
{
+#ifdef USE_MAPPED_LOCATION
+ source_location location;
+#else
location_t *locus;
+#endif
tree last;
edge e;
if (TREE_THIS_VOLATILE (cfun->decl)
&& EXIT_BLOCK_PTR->pred != NULL)
{
+#ifdef USE_MAPPED_LOCATION
+ location = UNKNOWN_LOCATION;
+#else
locus = NULL;
+#endif
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
{
last = last_stmt (e->src);
if (TREE_CODE (last) == RETURN_EXPR
+#ifdef USE_MAPPED_LOCATION
+ && (location = EXPR_LOCATION (last)) != UNKNOWN_LOCATION)
+#else
&& (locus = EXPR_LOCUS (last)) != NULL)
+#endif
break;
}
+#ifdef USE_MAPPED_LOCATION
+ if (location == UNKNOWN_LOCATION)
+ location = cfun->function_end_locus;
+ warning ("%H`noreturn' function does return", &location);
+#else
if (!locus)
locus = &cfun->function_end_locus;
warning ("%H`noreturn' function does return", locus);
+#endif
}
/* If we see "return;" in some basic block, then we do reach the end
if (TREE_CODE (last) == RETURN_EXPR
&& TREE_OPERAND (last, 0) == NULL)
{
+#ifdef USE_MAPPED_LOCATION
+ location = EXPR_LOCATION (last);
+ if (location == UNKNOWN_LOCATION)
+ location = cfun->function_end_locus;
+ warning ("%Hcontrol reaches end of non-void function", &location);
+#else
locus = EXPR_LOCUS (last);
if (!locus)
locus = &cfun->function_end_locus;
warning ("%Hcontrol reaches end of non-void function", locus);
+#endif
break;
}
}
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
- PROP_ssa, /* properties_required */
+ PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */