re PR tree-optimization/41857 (Loop optimizer breaks __ea pointers with -mea64)

gcc/
	PR tree-optimization/41857
	* tree-flow.h (rewrite_use_address): Add BASE_HINT argument.
	* tree-ssa-loop-ivopts.c (rewrite_use_address): Pass base hint
	to create_mem_ref.
	* tree-ssa-address.c (move_hint_to_base): New function.
	(most_expensive_mult_to_index): Add TYPE argument.  Use mode and
	address space associated with TYPE.
	(addr_to_parts): Add TYPE and BASE_HINT arguments.  Pass TYPE to
	most_expensive_mult_to_index.  Call move_hint_to_base.
	(create_mem_ref): Add BASE_HINT argument.  Pass BASE_HINT and
	TYPE to addr_to_parts.

gcc/testsuite/
	PR tree-optimization/41857
	* gcc.target/spu/ea/pr41857.c: New file.

From-SVN: r153810
This commit is contained in:
Ulrich Weigand 2009-11-02 14:30:39 +00:00 committed by Ulrich Weigand
parent 2b93f88dc5
commit d7c0c068dd
6 changed files with 111 additions and 16 deletions

View File

@ -1,3 +1,17 @@
2009-11-02 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
PR tree-optimization/41857
* tree-flow.h (rewrite_use_address): Add BASE_HINT argument.
* tree-ssa-loop-ivopts.c (rewrite_use_address): Pass base hint
to create_mem_ref.
* tree-ssa-address.c (move_hint_to_base): New function.
(most_expensive_mult_to_index): Add TYPE argument. Use mode and
address space associated with TYPE.
(addr_to_parts): Add TYPE and BASE_HINT arguments. Pass TYPE to
most_expensive_mult_to_index. Call move_hint_to_base.
(create_mem_ref): Add BASE_HINT argument. Pass BASE_HINT and
TYPE to addr_to_parts.
2009-11-02 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/41750

View File

@ -1,3 +1,8 @@
2009-11-02 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
PR tree-optimization/41857
* gcc.target/spu/ea/pr41857.c: New file.
2009-11-02 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/41750

View File

@ -0,0 +1,29 @@
/* Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
any later version.
This file is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with this file; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* { dg-do compile } */
__ea char *strchr_ea (__ea const char *s, int c);
__ea char *foo (__ea char *s)
{
__ea char *ret = s;
int i;
for (i = 0; i < 3; i++)
ret = strchr_ea (ret, s[i]);
return ret;
}

View File

@ -921,7 +921,7 @@ struct mem_address
struct affine_tree_combination;
tree create_mem_ref (gimple_stmt_iterator *, tree,
struct affine_tree_combination *, bool);
struct affine_tree_combination *, tree, bool);
rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
void get_address_description (tree, struct mem_address *);
tree maybe_fold_tmr (tree);

View File

@ -392,6 +392,33 @@ move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
aff_combination_remove_elt (addr, i);
}
/* If ADDR contains an instance of BASE_HINT, move it to PARTS->base. */
static void
move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
aff_tree *addr)
{
unsigned i;
tree val = NULL_TREE;
for (i = 0; i < addr->n; i++)
{
if (!double_int_one_p (addr->elts[i].coef))
continue;
val = addr->elts[i].val;
if (operand_equal_p (val, base_hint, 0))
break;
}
if (i == addr->n)
return;
/* Cast value to appropriate pointer type. */
parts->base = fold_convert (build_pointer_type (type), val);
aff_combination_remove_elt (addr, i);
}
/* If ADDR contains an address of a dereferenced pointer, move it to
PARTS->base. */
@ -453,9 +480,11 @@ add_to_parts (struct mem_address *parts, tree elt)
element(s) to PARTS. */
static void
most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
bool speed)
most_expensive_mult_to_index (tree type, struct mem_address *parts,
aff_tree *addr, bool speed)
{
addr_space_t as = TYPE_ADDR_SPACE (type);
enum machine_mode address_mode = targetm.addr_space.address_mode (as);
HOST_WIDE_INT coef;
double_int best_mult, amult, amult_neg;
unsigned best_mult_cost = 0, acost;
@ -469,15 +498,12 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
continue;
/* FIXME: Should use the correct memory mode rather than Pmode. */
coef = double_int_to_shwi (addr->elts[i].coef);
if (coef == 1
|| !multiplier_allowed_in_address_p (coef, Pmode,
ADDR_SPACE_GENERIC))
|| !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
continue;
acost = multiply_by_cost (coef, Pmode, speed);
acost = multiply_by_cost (coef, address_mode, speed);
if (acost > best_mult_cost)
{
@ -520,8 +546,10 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
parts->step = double_int_to_tree (sizetype, best_mult);
}
/* Splits address ADDR into PARTS.
/* Splits address ADDR for a memory access of type TYPE into PARTS.
If BASE_HINT is non-NULL, it specifies an SSA name to be used
preferentially as base of the reference.
TODO -- be more clever about the distribution of the elements of ADDR
to PARTS. Some architectures do not support anything but single
register in address, possibly with a small integer offset; while
@ -530,7 +558,8 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
addressing modes is useless. */
static void
addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
addr_to_parts (tree type, aff_tree *addr, tree base_hint,
struct mem_address *parts, bool speed)
{
tree part;
unsigned i;
@ -550,12 +579,14 @@ addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
/* First move the most expensive feasible multiplication
to index. */
most_expensive_mult_to_index (parts, addr, speed);
most_expensive_mult_to_index (type, parts, addr, speed);
/* Try to find a base of the reference. Since at the moment
there is no reliable way how to distinguish between pointer and its
offset, this is just a guess. */
if (!parts->symbol)
if (!parts->symbol && base_hint)
move_hint_to_base (type, parts, base_hint, addr);
if (!parts->symbol && !parts->base)
move_pointer_to_base (parts, addr);
/* Then try to process the remaining elements. */
@ -592,13 +623,13 @@ gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
tree
create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
bool speed)
tree base_hint, bool speed)
{
tree mem_ref, tmp;
tree atype;
struct mem_address parts;
addr_to_parts (addr, &parts, speed);
addr_to_parts (type, addr, base_hint, &parts, speed);
gimplify_mem_ref_parts (gsi, &parts);
mem_ref = create_mem_ref_raw (type, &parts);
if (mem_ref)

View File

@ -5510,6 +5510,7 @@ rewrite_use_address (struct ivopts_data *data,
{
aff_tree aff;
gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
tree base_hint = NULL_TREE;
tree ref;
bool ok;
@ -5517,7 +5518,22 @@ rewrite_use_address (struct ivopts_data *data,
gcc_assert (ok);
unshare_aff_combination (&aff);
ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff, data->speed);
/* To avoid undefined overflow problems, all IV candidates use unsigned
integer types. The drawback is that this makes it impossible for
create_mem_ref to distinguish an IV that is based on a memory object
from one that represents simply an offset.
To work around this problem, we pass a hint to create_mem_ref that
indicates which variable (if any) in aff is an IV based on a memory
object. Note that we only consider the candidate. If this is not
based on an object, the base of the reference is in some subexpression
of the use -- but these will use pointer types, so they are recognized
by the create_mem_ref heuristics anyway. */
if (cand->iv->base_object)
base_hint = var_at_stmt (data->current_loop, cand, use->stmt);
ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff, base_hint,
data->speed);
copy_ref_info (ref, *use->op_p);
*use->op_p = ref;
}