return false;
}
-/* Return true iff type of EXP is not sufficiently aligned. */
+/* Return true if EXP is a memory reference less aligned than ALIGN. This is
+ invoked only on strict-alignment targets. */
static bool
-tree_non_mode_aligned_mem_p (tree exp)
+tree_non_aligned_mem_p (tree exp, unsigned int align)
{
- enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
- unsigned int align;
+ unsigned int exp_align;
if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
exp = TREE_OPERAND (exp, 0);
- if (TREE_CODE (exp) == SSA_NAME
- || TREE_CODE (exp) == MEM_REF
- || mode == BLKmode
- || is_gimple_min_invariant (exp)
- || !STRICT_ALIGNMENT)
+ if (TREE_CODE (exp) == SSA_NAME || is_gimple_min_invariant (exp))
return false;
- align = get_object_alignment (exp);
- if (GET_MODE_ALIGNMENT (mode) > align)
+ /* get_object_alignment will fall back to BITS_PER_UNIT if it cannot
+ compute an explicit alignment. Pretend that dereferenced pointers
+ are always aligned on strict-alignment targets. */
+ if (TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == TARGET_MEM_REF)
+ exp_align = get_object_or_type_alignment (exp);
+ else
+ exp_align = get_object_alignment (exp);
+
+ if (exp_align < align)
return true;
return false;
tree lhs, rhs;
struct access *lacc, *racc;
- if (!gimple_assign_single_p (stmt))
+ if (!gimple_assign_single_p (stmt)
+ /* Scope clobbers don't influence scalarization. */
+ || gimple_clobber_p (stmt))
return false;
lhs = gimple_assign_lhs (stmt);
if (lacc)
{
lacc->grp_assignment_write = 1;
- lacc->grp_unscalarizable_region |= tree_non_mode_aligned_mem_p (rhs);
+ if (STRICT_ALIGNMENT
+ && tree_non_aligned_mem_p (rhs, get_object_alignment (lhs)))
+ lacc->grp_unscalarizable_region = 1;
}
if (racc)
if (should_scalarize_away_bitmap && !gimple_has_volatile_ops (stmt)
&& !is_gimple_reg_type (racc->type))
bitmap_set_bit (should_scalarize_away_bitmap, DECL_UID (racc->base));
- racc->grp_unscalarizable_region |= tree_non_mode_aligned_mem_p (lhs);
+ if (STRICT_ALIGNMENT
+ && tree_non_aligned_mem_p (lhs, get_object_alignment (rhs)))
+ racc->grp_unscalarizable_region = 1;
}
if (lacc && racc
return fold_build2_loc (loc, MEM_REF, exp_type, base, off);
}
+DEF_VEC_ALLOC_P_STACK (tree);
+#define VEC_tree_stack_alloc(alloc) VEC_stack_alloc (tree, alloc)
+
/* Construct a memory reference to a part of an aggregate BASE at the given
- OFFSET and of the same type as MODEL. In case this is a reference to a
- component, the function will replicate the last COMPONENT_REF of model's
- expr to access it. GSI and INSERT_AFTER have the same meaning as in
- build_ref_for_offset. */
+ OFFSET and of the type of MODEL. In case this is a chain of references
+ to component, the function will replicate the chain of COMPONENT_REFs of
+ the expression of MODEL to access it. GSI and INSERT_AFTER have the same
+ meaning as in build_ref_for_offset. */
static tree
build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
struct access *model, gimple_stmt_iterator *gsi,
bool insert_after)
{
+ tree type = model->type, t;
+ VEC(tree,stack) *cr_stack = NULL;
+
if (TREE_CODE (model->expr) == COMPONENT_REF)
{
- tree t, exp_type, fld = TREE_OPERAND (model->expr, 1);
- tree cr_offset = component_ref_field_offset (model->expr);
-
- gcc_assert (cr_offset && host_integerp (cr_offset, 1));
- offset -= TREE_INT_CST_LOW (cr_offset) * BITS_PER_UNIT;
- offset -= TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld));
- exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
- t = build_ref_for_offset (loc, base, offset, exp_type, gsi, insert_after);
- return fold_build3_loc (loc, COMPONENT_REF, model->type, t, fld,
- TREE_OPERAND (model->expr, 2));
+ tree expr = model->expr;
+
+ /* Create a stack of the COMPONENT_REFs so later we can walk them in
+ order from inner to outer. */
+ cr_stack = VEC_alloc (tree, stack, 6);
+
+ do {
+ tree field = TREE_OPERAND (expr, 1);
+ tree cr_offset = component_ref_field_offset (expr);
+ gcc_assert (cr_offset && host_integerp (cr_offset, 1));
+
+ offset -= TREE_INT_CST_LOW (cr_offset) * BITS_PER_UNIT;
+ offset -= TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+
+ VEC_safe_push (tree, stack, cr_stack, expr);
+
+ expr = TREE_OPERAND (expr, 0);
+ type = TREE_TYPE (expr);
+ } while (TREE_CODE (expr) == COMPONENT_REF);
}
- else
- return build_ref_for_offset (loc, base, offset, model->type,
- gsi, insert_after);
+
+ t = build_ref_for_offset (loc, base, offset, type, gsi, insert_after);
+
+ if (TREE_CODE (model->expr) == COMPONENT_REF)
+ {
+ unsigned i;
+ tree expr;
+
+ /* Now replicate the chain of COMPONENT_REFs from inner to outer. */
+ FOR_EACH_VEC_ELT_REVERSE (tree, cr_stack, i, expr)
+ {
+ tree field = TREE_OPERAND (expr, 1);
+ t = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (field), t, field,
+ TREE_OPERAND (expr, 2));
+ }
+
+ VEC_free (tree, stack, cr_stack);
+ }
+
+ return t;
}
/* Construct a memory reference consisting of component_refs and array_refs to
|| ((root->grp_scalar_read || root->grp_assignment_read)
&& (root->grp_scalar_write || root->grp_assignment_write))))
{
+ bool new_integer_type;
+ if (TREE_CODE (root->type) == ENUMERAL_TYPE)
+ {
+ tree rt = root->type;
+ root->type = build_nonstandard_integer_type (TYPE_PRECISION (rt),
+ TYPE_UNSIGNED (rt));
+ new_integer_type = true;
+ }
+ else
+ new_integer_type = false;
+
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Marking ");
print_generic_expr (dump_file, root->base, 0);
- fprintf (dump_file, " offset: %u, size: %u: ",
+ fprintf (dump_file, " offset: %u, size: %u ",
(unsigned) root->offset, (unsigned) root->size);
- fprintf (dump_file, " to be replaced.\n");
+ fprintf (dump_file, " to be replaced%s.\n",
+ new_integer_type ? " with an integer": "");
}
root->grp_to_be_replaced = 1;
|| racc->grp_unscalarizable_region)
return false;
- if (!lacc->first_child && !racc->first_child
- && is_gimple_reg_type (racc->type))
+ if (is_gimple_reg_type (racc->type))
{
- tree t = lacc->base;
-
- lacc->type = racc->type;
- if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t), lacc->offset,
- racc->type))
- lacc->expr = t;
- else
+ if (!lacc->first_child && !racc->first_child)
{
- lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
- lacc->base, lacc->offset,
- racc, NULL, false);
- lacc->grp_no_warning = true;
+ tree t = lacc->base;
+
+ lacc->type = racc->type;
+ if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t),
+ lacc->offset, racc->type))
+ lacc->expr = t;
+ else
+ {
+ lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
+ lacc->base, lacc->offset,
+ racc, NULL, false);
+ lacc->grp_no_warning = true;
+ }
}
return false;
}
rhs = get_access_replacement (racc);
if (!useless_type_conversion_p (lacc->type, racc->type))
rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, lacc->type, rhs);
+
+ if (racc->grp_partial_lhs && lacc->grp_partial_lhs)
+ rhs = force_gimple_operand_gsi (old_gsi, rhs, true, NULL_TREE,
+ true, GSI_SAME_STMT);
}
else
{
else
rhs = build_ref_for_model (loc, top_racc->base, offset, lacc,
new_gsi, true);
+ if (lacc->grp_partial_lhs)
+ rhs = force_gimple_operand_gsi (new_gsi, rhs, true, NULL_TREE,
+ false, GSI_NEW_STMT);
}
stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
|| gimple_code (access->stmt) == GIMPLE_ASM))
return true;
- if (tree_non_mode_aligned_mem_p (access->expr))
+ if (STRICT_ALIGNMENT
+ && tree_non_aligned_mem_p (access->expr, TYPE_ALIGN (access->type)))
return true;
return false;
VEC (cgraph_edge_p, heap) * redirect_callers = collect_callers_of_node (node);
rebuild_cgraph_edges ();
+ free_dominance_info (CDI_DOMINATORS);
pop_cfun ();
current_function_decl = NULL_TREE;