re-distribute it when the conditional expands into multiple conditionals.
This is however difficult to do. */
static void
-add_reg_br_prob_note (FILE *dump_file, rtx last, int probability)
+add_reg_br_prob_note (rtx last, int probability)
{
if (profile_status == PROFILE_ABSENT)
return;
}
frame_offset = new_frame_offset;
+ if (frame_offset_overflow (frame_offset, cfun->decl))
+ frame_offset = offset = 0;
+
return offset;
}
gcc_assert (index < stack_vars_conflict_alloc);
return stack_vars_conflict[index];
}
-
+
+/* Returns true if TYPE is or contains a union type. */
+
+static bool
+aggregate_contains_union_type (tree type)
+{
+ tree field;
+
+ if (TREE_CODE (type) == UNION_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE)
+ return true;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return aggregate_contains_union_type (TREE_TYPE (type));
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return false;
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ if (aggregate_contains_union_type (TREE_TYPE (field)))
+ return true;
+
+ return false;
+}
+
/* A subroutine of expand_used_vars. If two variables X and Y have alias
sets that do not conflict, then do add a conflict for these variables
- in the interference graph. We also have to mind MEM_IN_STRUCT_P and
- MEM_SCALAR_P. */
+ in the interference graph. We also need to make sure to add conflicts
+ for union containing structures. Else RTL alias analysis comes along
+ and due to type based aliasing rules decides that for two overlapping
+ union temporaries { short s; int i; } accesses to the same mem through
+ different types may not alias and happily reorders stores across
+ life-time boundaries of the temporaries (See PR25654).
+ We also have to mind MEM_IN_STRUCT_P and MEM_SCALAR_P. */
static void
add_alias_set_conflicts (void)
for (i = 0; i < n; ++i)
{
- bool aggr_i = AGGREGATE_TYPE_P (TREE_TYPE (stack_vars[i].decl));
- HOST_WIDE_INT set_i = get_alias_set (stack_vars[i].decl);
+ tree type_i = TREE_TYPE (stack_vars[i].decl);
+ bool aggr_i = AGGREGATE_TYPE_P (type_i);
+ bool contains_union;
+ contains_union = aggregate_contains_union_type (type_i);
for (j = 0; j < i; ++j)
{
- bool aggr_j = AGGREGATE_TYPE_P (TREE_TYPE (stack_vars[j].decl));
- HOST_WIDE_INT set_j = get_alias_set (stack_vars[j].decl);
- if (aggr_i != aggr_j || !alias_sets_conflict_p (set_i, set_j))
+ tree type_j = TREE_TYPE (stack_vars[j].decl);
+ bool aggr_j = AGGREGATE_TYPE_P (type_j);
+ if (aggr_i != aggr_j
+ /* Either the objects conflict by means of type based
+ aliasing rules, or we need to add a conflict. */
+ || !objects_must_conflict_p (type_i, type_j)
+ /* In case the types do not conflict ensure that access
+ to elements will conflict. In case of unions we have
+ to be careful as type based aliasing rules may say
+ access to the same memory does not conflict. So play
+ safe and add a conflict in this case. */
+ || contains_union)
add_stack_var_conflict (i, j);
}
}
if (TREE_CODE (then_exp) == GOTO_EXPR && IS_EMPTY_STMT (else_exp))
{
jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
- add_reg_br_prob_note (dump_file, last, true_edge->probability);
+ add_reg_br_prob_note (last, true_edge->probability);
maybe_dump_rtl_for_tree_stmt (stmt, last);
if (EXPR_LOCUS (then_exp))
emit_line_note (*(EXPR_LOCUS (then_exp)));
if (TREE_CODE (else_exp) == GOTO_EXPR && IS_EMPTY_STMT (then_exp))
{
jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_exp)));
- add_reg_br_prob_note (dump_file, last, false_edge->probability);
+ add_reg_br_prob_note (last, false_edge->probability);
maybe_dump_rtl_for_tree_stmt (stmt, last);
if (EXPR_LOCUS (else_exp))
emit_line_note (*(EXPR_LOCUS (else_exp)));
&& TREE_CODE (else_exp) == GOTO_EXPR);
jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
- add_reg_br_prob_note (dump_file, last, true_edge->probability);
+ add_reg_br_prob_note (last, true_edge->probability);
last = get_last_insn ();
expand_expr (else_exp, const0_rtx, VOIDmode, 0);
/* Expand basic block BB from GIMPLE trees to RTL. */
static basic_block
-expand_gimple_basic_block (basic_block bb, FILE * dump_file)
+expand_gimple_basic_block (basic_block bb)
{
block_stmt_iterator bsi = bsi_start (bb);
tree stmt = NULL;
update_bb_for_insn (exit_block);
}
+/* Helper function for discover_nonconstant_array_refs.
+ Look for ARRAY_REF nodes with non-constant indexes and mark them
+ addressable. */
+
+static tree
+discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
+{
+ tree t = *tp;
+
+ if (IS_TYPE_OR_DECL_P (t))
+ *walk_subtrees = 0;
+ else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+ && is_gimple_min_invariant (TREE_OPERAND (t, 1))
+ && (!TREE_OPERAND (t, 2)
+ || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
+ || (TREE_CODE (t) == COMPONENT_REF
+ && (!TREE_OPERAND (t,2)
+ || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
+ || TREE_CODE (t) == BIT_FIELD_REF
+ || TREE_CODE (t) == REALPART_EXPR
+ || TREE_CODE (t) == IMAGPART_EXPR
+ || TREE_CODE (t) == VIEW_CONVERT_EXPR
+ || TREE_CODE (t) == NOP_EXPR
+ || TREE_CODE (t) == CONVERT_EXPR)
+ t = TREE_OPERAND (t, 0);
+
+ if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+ {
+ t = get_base_address (t);
+ if (t && DECL_P (t))
+ TREE_ADDRESSABLE (t) = 1;
+ }
+
+ *walk_subtrees = 0;
+ }
+
+ return NULL_TREE;
+}
+
+/* RTL expansion is not able to compile array references with variable
+ offsets for arrays stored in single register. Discover such
+ expressions and mark variables as addressable to avoid this
+ scenario. */
+
+static void
+discover_nonconstant_array_refs (void)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+
+ FOR_EACH_BB (bb)
+ {
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ walk_tree (bsi_stmt_ptr (bsi), discover_nonconstant_array_refs_r,
+ NULL , NULL);
+ }
+}
+
/* Translate the intermediate representation contained in the CFG
from GIMPLE trees to RTL.
confuse the CFG hooks, so be careful to not manipulate CFG during
the expansion. */
-static void
+static unsigned int
tree_expand_cfg (void)
{
basic_block bb, init_block;
/* Prepare the rtl middle end to start recording block changes. */
reset_block_changes ();
+ /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE. */
+ discover_nonconstant_array_refs ();
+
/* Expand the variables recorded during gimple lowering. */
expand_used_vars ();
init_block = construct_init_block ();
FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb)
- bb = expand_gimple_basic_block (bb, dump_file);
+ bb = expand_gimple_basic_block (bb);
construct_exit_block ();
(*debug_hooks->outlining_inline_function) (current_function_decl);
TREE_ASM_WRITTEN (current_function_decl) = 1;
+
+ /* After expanding, the return labels are no longer needed. */
+ return_label = NULL;
+ naked_return_label = NULL;
+ return 0;
}
struct tree_opt_pass pass_expand =
/* ??? If TER is enabled, we actually receive GENERIC. */
PROP_gimple_leh | PROP_cfg, /* properties_required */
PROP_rtl, /* properties_provided */
- PROP_gimple_leh, /* properties_destroyed */
+ PROP_trees, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
'r' /* letter */