/* Control flow functions for trees.
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010, 2011 Free Software Foundation, Inc.
+ 2010, 2011, 2012 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
/* This hash table allows us to efficiently lookup all CASE_LABEL_EXPRs
which use a particular edge. The CASE_LABEL_EXPRs are chained together
- via their TREE_CHAIN field, which we clear after we're done with the
+ via their CASE_CHAIN field, which we clear after we're done with the
hash table to prevent problems with duplication of GIMPLE_SWITCHes.
Access to this list of CASE_LABEL_EXPRs allows us to efficiently
if (start_new_block || stmt_starts_bb_p (stmt, prev_stmt))
{
if (!first_stmt_of_seq)
- seq = gsi_split_seq_before (&i);
+ gsi_split_seq_before (&i, &seq);
bb = create_basic_block (seq, NULL, bb);
start_new_block = false;
}
bb->index = last_basic_block;
bb->flags = BB_NEW;
- bb->il.gimple = ggc_alloc_cleared_gimple_bb_info ();
- set_bb_seq (bb, h ? (gimple_seq) h : gimple_seq_alloc ());
+ set_bb_seq (bb, h ? (gimple_seq) h : NULL);
/* Add the new block to the linked list of blocks. */
link_block (bb, after);
/* This can only occur for virtual operands, since
for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
would prevent replacement. */
- gcc_assert (!is_gimple_reg (name));
+ gcc_checking_assert (!is_gimple_reg (name));
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
}
}
gimple orig_stmt = stmt;
size_t i;
- fold_stmt (&gsi);
- stmt = gsi_stmt (gsi);
- if (cfgcleanup_altered_bbs && !is_gimple_debug (stmt))
+ /* Mark the block if we changed the last stmt in it. */
+ if (cfgcleanup_altered_bbs
+ && stmt_ends_bb_p (stmt))
bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
- /* FIXME. This should go in update_stmt. */
- for (i = 0; i < gimple_num_ops (stmt); i++)
- {
- tree op = gimple_op (stmt, i);
- /* Operands may be empty here. For example, the labels
- of a GIMPLE_COND are nulled out following the creation
- of the corresponding CFG edges. */
- if (op && TREE_CODE (op) == ADDR_EXPR)
- recompute_tree_invariant_for_addr_expr (op);
- }
+ /* FIXME. It shouldn't be required to keep TREE_CONSTANT
+ on ADDR_EXPRs up-to-date on GIMPLE. Propagation will
+ only change sth from non-invariant to invariant, and only
+ when propagating constants. */
+ if (is_gimple_min_invariant (val))
+ for (i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ tree op = gimple_op (stmt, i);
+ /* Operands may be empty here. For example, the labels
+ of a GIMPLE_COND are nulled out following the creation
+ of the corresponding CFG edges. */
+ if (op && TREE_CODE (op) == ADDR_EXPR)
+ recompute_tree_invariant_for_addr_expr (op);
+ }
+
+ if (fold_stmt (&gsi))
+ stmt = gsi_stmt (gsi);
+
+ if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
+ gimple_purge_dead_eh_edges (gimple_bb (stmt));
- maybe_clean_or_replace_eh_stmt (orig_stmt, stmt);
update_stmt (stmt);
}
}
- gcc_assert (has_zero_uses (name));
+ gcc_checking_assert (has_zero_uses (name));
/* Also update the trees stored in loop structures. */
if (current_loops)
gimple_merge_blocks (basic_block a, basic_block b)
{
gimple_stmt_iterator last, gsi, psi;
- gimple_seq phis = phi_nodes (b);
if (dump_file)
fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index);
/* Remove all single-valued PHI nodes from block B of the form
V_i = PHI <V_j> by propagating V_j to all the uses of V_i. */
gsi = gsi_last_bb (a);
- for (psi = gsi_start (phis); !gsi_end_p (psi); )
+ for (psi = gsi_start_phis (b); !gsi_end_p (psi); )
{
gimple phi = gsi_stmt (psi);
tree def = gimple_phi_result (phi), use = gimple_phi_arg_def (phi, 0);
}
remove_phi_nodes_and_edges_for_unreachable_block (bb);
- bb->il.gimple = NULL;
+ bb->il.gimple.seq = NULL;
+ bb->il.gimple.phi_nodes = NULL;
}
Miscellaneous helpers
---------------------------------------------------------------------------*/
+/* Return true if T, a GIMPLE_CALL, can make an abnormal transfer of control
+ flow. Transfers of control flow associated with EH are excluded. */
+
+static bool
+call_can_make_abnormal_goto (gimple t)
+{
+ /* If the function has no non-local labels, then a call cannot make an
+ abnormal transfer of control. */
+ if (!cfun->has_nonlocal_label)
+ return false;
+
+ /* Likewise if the call has no side effects. */
+ if (!gimple_has_side_effects (t))
+ return false;
+
+ /* Likewise if the called function is leaf. */
+ if (gimple_call_flags (t) & ECF_LEAF)
+ return false;
+
+ return true;
+}
+
+
+/* Return true if T can make an abnormal transfer of control flow.
+ Transfers of control flow associated with EH are excluded. */
+
+bool
+stmt_can_make_abnormal_goto (gimple t)
+{
+ if (computed_goto_p (t))
+ return true;
+ if (is_gimple_call (t))
+ return call_can_make_abnormal_goto (t);
+ return false;
+}
+
+
/* Return true if T represents a stmt that always transfers control. */
bool
{
int flags = gimple_call_flags (t);
- /* A non-pure/const call alters flow control if the current
- function has nonlocal labels. */
- if (!(flags & (ECF_CONST | ECF_PURE | ECF_LEAF))
- && cfun->has_nonlocal_label)
+ /* A call alters control flow if it can make an abnormal goto. */
+ if (call_can_make_abnormal_goto (t))
return true;
/* A call also alters control flow if it does not return. */
}
-/* Return true if T can make an abnormal transfer of control flow.
- Transfers of control flow associated with EH are excluded. */
-
-bool
-stmt_can_make_abnormal_goto (gimple t)
-{
- if (computed_goto_p (t))
- return true;
- if (is_gimple_call (t))
- return (gimple_has_side_effects (t) && cfun->has_nonlocal_label
- && !(gimple_call_flags (t) & ECF_LEAF));
- return false;
-}
-
-
/* Return true if STMT should start a new basic block. PREV_STMT is
the statement preceding STMT. It is used when STMT is a label or a
case label. Labels should only start a new basic block if their
error ("invalid position or size operand to BIT_FIELD_REF");
return t;
}
- else if (INTEGRAL_TYPE_P (TREE_TYPE (t))
- && (TYPE_PRECISION (TREE_TYPE (t))
- != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
+ if (INTEGRAL_TYPE_P (TREE_TYPE (t))
+ && (TYPE_PRECISION (TREE_TYPE (t))
+ != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
{
error ("integral result type precision does not match "
"field size of BIT_FIELD_REF");
return t;
}
- if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
- && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (t)))
- != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ && !AGGREGATE_TYPE_P (TREE_TYPE (t))
+ && TYPE_MODE (TREE_TYPE (t)) != BLKmode
+ && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (t)))
+ != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
{
error ("mode precision of non-integral result does not "
"match field size of BIT_FIELD_REF");
{
CASE_CONVERT:
{
- /* Allow conversions between integral types and pointers only if
+ /* Allow conversions from pointer type to integral type only if
there is no sign or zero extension involved.
For targets were the precision of ptrofftype doesn't match that
- of pointers we need to allow arbitrary conversions from and
- to ptrofftype. */
+ of pointers we need to allow arbitrary conversions to ptrofftype. */
if ((POINTER_TYPE_P (lhs_type)
- && INTEGRAL_TYPE_P (rhs1_type)
- && (TYPE_PRECISION (lhs_type) >= TYPE_PRECISION (rhs1_type)
- || ptrofftype_p (rhs1_type)))
+ && INTEGRAL_TYPE_P (rhs1_type))
|| (POINTER_TYPE_P (rhs1_type)
&& INTEGRAL_TYPE_P (lhs_type)
&& (TYPE_PRECISION (rhs1_type) >= TYPE_PRECISION (lhs_type)
|| ptrofftype_p (sizetype))))
return false;
- /* Allow conversion from integer to offset type and vice versa. */
+ /* Allow conversion from integral to offset type and vice versa. */
if ((TREE_CODE (lhs_type) == OFFSET_TYPE
- && TREE_CODE (rhs1_type) == INTEGER_TYPE)
- || (TREE_CODE (lhs_type) == INTEGER_TYPE
+ && INTEGRAL_TYPE_P (rhs1_type))
+ || (INTEGRAL_TYPE_P (lhs_type)
&& TREE_CODE (rhs1_type) == OFFSET_TYPE))
return false;
case VEC_PACK_TRUNC_EXPR:
case VEC_PACK_SAT_EXPR:
case VEC_PACK_FIX_TRUNC_EXPR:
- case VEC_EXTRACT_EVEN_EXPR:
- case VEC_EXTRACT_ODD_EXPR:
- case VEC_INTERLEAVE_HIGH_EXPR:
- case VEC_INTERLEAVE_LOW_EXPR:
/* FIXME. */
return false;
static bool
verify_gimple_switch (gimple stmt)
{
+ unsigned int i, n;
+ tree elt, prev_upper_bound = NULL_TREE;
+ tree index_type, elt_type = NULL_TREE;
+
if (!is_gimple_val (gimple_switch_index (stmt)))
{
error ("invalid operand to switch statement");
return true;
}
+ index_type = TREE_TYPE (gimple_switch_index (stmt));
+ if (! INTEGRAL_TYPE_P (index_type))
+ {
+ error ("non-integral type switch statement");
+ debug_generic_expr (index_type);
+ return true;
+ }
+
+ elt = gimple_switch_default_label (stmt);
+ if (CASE_LOW (elt) != NULL_TREE || CASE_HIGH (elt) != NULL_TREE)
+ {
+ error ("invalid default case label in switch statement");
+ debug_generic_expr (elt);
+ return true;
+ }
+
+ n = gimple_switch_num_labels (stmt);
+ for (i = 1; i < n; i++)
+ {
+ elt = gimple_switch_label (stmt, i);
+
+ if (! CASE_LOW (elt))
+ {
+ error ("invalid case label in switch statement");
+ debug_generic_expr (elt);
+ return true;
+ }
+ if (CASE_HIGH (elt)
+ && ! tree_int_cst_lt (CASE_LOW (elt), CASE_HIGH (elt)))
+ {
+ error ("invalid case range in switch statement");
+ debug_generic_expr (elt);
+ return true;
+ }
+
+ if (elt_type)
+ {
+ if (TREE_TYPE (CASE_LOW (elt)) != elt_type
+ || (CASE_HIGH (elt) && TREE_TYPE (CASE_HIGH (elt)) != elt_type))
+ {
+ error ("type mismatch for case label in switch statement");
+ debug_generic_expr (elt);
+ return true;
+ }
+ }
+ else
+ {
+ elt_type = TREE_TYPE (CASE_LOW (elt));
+ if (TYPE_PRECISION (index_type) < TYPE_PRECISION (elt_type))
+ {
+ error ("type precision mismatch in switch statement");
+ return true;
+ }
+ }
+
+ if (prev_upper_bound)
+ {
+ if (! tree_int_cst_lt (prev_upper_bound, CASE_LOW (elt)))
+ {
+ error ("case labels not sorted in switch statement");
+ return true;
+ }
+ }
+
+ prev_upper_bound = CASE_HIGH (elt);
+ if (! prev_upper_bound)
+ prev_upper_bound = CASE_LOW (elt);
+ }
+
return false;
}
edge e;
edge_iterator ei;
- if (ENTRY_BLOCK_PTR->il.gimple)
+ if (ENTRY_BLOCK_PTR->il.gimple.seq || ENTRY_BLOCK_PTR->il.gimple.phi_nodes)
{
error ("ENTRY_BLOCK has IL associated with it");
err = 1;
}
- if (EXIT_BLOCK_PTR->il.gimple)
+ if (EXIT_BLOCK_PTR->il.gimple.seq || EXIT_BLOCK_PTR->il.gimple.phi_nodes)
{
error ("EXIT_BLOCK has IL associated with it");
err = 1;
brings ugly quadratic memory consumption in the inliner.
(We are still quadratic since we need to update stmt BB pointers,
sadly.) */
- list = gsi_split_seq_before (&gsi);
+ gsi_split_seq_before (&gsi, &list);
set_bb_seq (new_bb, list);
for (gsi_tgt = gsi_start (list);
!gsi_end_p (gsi_tgt); gsi_next (&gsi_tgt))
return true;
}
+/* Checks if BB is part of the region defined by N_REGION BBS. */
+static bool
+bb_part_of_region_p (basic_block bb, basic_block* bbs, unsigned n_region)
+{
+ unsigned int n;
+
+ for (n = 0; n < n_region; n++)
+ {
+ if (bb == bbs[n])
+ return true;
+ }
+ return false;
+}
+
/* Duplicates REGION consisting of N_REGION blocks. The new blocks
are stored to REGION_COPY in the same order in that they appear
in REGION, if REGION_COPY is not NULL. ENTRY is the entry to
gimple_stmt_iterator psi;
gimple phi;
tree def;
+ struct loop *target, *aloop, *cloop;
gcc_assert (EDGE_COUNT (exit->src->succs) == 2);
exits[0] = exit;
initialize_original_copy_tables ();
set_loop_copy (orig_loop, loop);
- duplicate_subloops (orig_loop, loop);
+
+ target= loop;
+ for (aloop = orig_loop->inner; aloop; aloop = aloop->next)
+ {
+ if (bb_part_of_region_p (aloop->header, region, n_region))
+ {
+ cloop = duplicate_loop (aloop, target);
+ duplicate_subloops (aloop, cloop);
+ }
+ }
if (!region_copy)
{
add_phi_arg (phi, def, e, gimple_phi_arg_location_from_edge (phi, e));
}
}
- e = redirect_edge_and_branch (nexits[0], nexits[1]->dest);
+ e = redirect_edge_and_branch (nexits[1], nexits[0]->dest);
PENDING_STMT (e) = NULL;
/* Anything that is outside of the region, but was dominated by something
p->remap_decls_p = false;
*handled_ops_p = true;
- walk_gimple_seq (gimple_omp_body (stmt), move_stmt_r,
- move_stmt_op, wi);
+ walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), move_stmt_r,
+ move_stmt_op, wi);
p->remap_decls_p = save_remap_decls_p;
}
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FORK))
return false;
- if (is_gimple_call (t)
- && !(call_flags & ECF_NORETURN))
- return true;
+ if (is_gimple_call (t))
+ {
+ edge_iterator ei;
+ edge e;
+ basic_block bb;
+
+ if (!(call_flags & ECF_NORETURN))
+ return true;
+
+ bb = gimple_bb (t);
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if ((e->flags & EDGE_FAKE) == 0)
+ return true;
+ }
if (gimple_code (t) == GIMPLE_ASM
&& (gimple_asm_volatile_p (t) || gimple_asm_input_p (t)))
/* Add fake edges to the function exit for any non constant and non
- noreturn calls, volatile inline assembly in the bitmap of blocks
- specified by BLOCKS or to the whole CFG if BLOCKS is zero. Return
- the number of blocks that were split.
+ noreturn calls (or noreturn calls with EH/abnormal edges),
+ volatile inline assembly in the bitmap of blocks specified by BLOCKS
+ or to the whole CFG if BLOCKS is zero. Return the number of blocks
+ that were split.
The goal is to expose cases in which entering a basic block does
not imply that all subsequent instructions must be executed. */