Commit d7c0c068 by Ulrich Weigand Committed by Ulrich Weigand

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
parent 2b93f88d
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> 2009-11-02 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/41750 PR tree-optimization/41750
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> 2009-11-02 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/41750 PR tree-optimization/41750
......
/* 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;
}
...@@ -921,7 +921,7 @@ struct mem_address ...@@ -921,7 +921,7 @@ struct mem_address
struct affine_tree_combination; struct affine_tree_combination;
tree create_mem_ref (gimple_stmt_iterator *, tree, 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); rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
void get_address_description (tree, struct mem_address *); void get_address_description (tree, struct mem_address *);
tree maybe_fold_tmr (tree); tree maybe_fold_tmr (tree);
......
...@@ -392,6 +392,33 @@ move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr) ...@@ -392,6 +392,33 @@ move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
aff_combination_remove_elt (addr, i); 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 /* If ADDR contains an address of a dereferenced pointer, move it to
PARTS->base. */ PARTS->base. */
...@@ -453,9 +480,11 @@ add_to_parts (struct mem_address *parts, tree elt) ...@@ -453,9 +480,11 @@ add_to_parts (struct mem_address *parts, tree elt)
element(s) to PARTS. */ element(s) to PARTS. */
static void static void
most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr, most_expensive_mult_to_index (tree type, struct mem_address *parts,
bool speed) 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; HOST_WIDE_INT coef;
double_int best_mult, amult, amult_neg; double_int best_mult, amult, amult_neg;
unsigned best_mult_cost = 0, acost; unsigned best_mult_cost = 0, acost;
...@@ -469,15 +498,12 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr, ...@@ -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)) if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
continue; continue;
/* FIXME: Should use the correct memory mode rather than Pmode. */
coef = double_int_to_shwi (addr->elts[i].coef); coef = double_int_to_shwi (addr->elts[i].coef);
if (coef == 1 if (coef == 1
|| !multiplier_allowed_in_address_p (coef, Pmode, || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
ADDR_SPACE_GENERIC))
continue; continue;
acost = multiply_by_cost (coef, Pmode, speed); acost = multiply_by_cost (coef, address_mode, speed);
if (acost > best_mult_cost) if (acost > best_mult_cost)
{ {
...@@ -520,8 +546,10 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr, ...@@ -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); 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 TODO -- be more clever about the distribution of the elements of ADDR
to PARTS. Some architectures do not support anything but single to PARTS. Some architectures do not support anything but single
register in address, possibly with a small integer offset; while 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, ...@@ -530,7 +558,8 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
addressing modes is useless. */ addressing modes is useless. */
static void 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; tree part;
unsigned i; unsigned i;
...@@ -550,12 +579,14 @@ addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed) ...@@ -550,12 +579,14 @@ addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
/* First move the most expensive feasible multiplication /* First move the most expensive feasible multiplication
to index. */ 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 /* Try to find a base of the reference. Since at the moment
there is no reliable way how to distinguish between pointer and its there is no reliable way how to distinguish between pointer and its
offset, this is just a guess. */ 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); move_pointer_to_base (parts, addr);
/* Then try to process the remaining elements. */ /* Then try to process the remaining elements. */
...@@ -592,13 +623,13 @@ gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts) ...@@ -592,13 +623,13 @@ gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
tree tree
create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr, create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
bool speed) tree base_hint, bool speed)
{ {
tree mem_ref, tmp; tree mem_ref, tmp;
tree atype; tree atype;
struct mem_address parts; 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); gimplify_mem_ref_parts (gsi, &parts);
mem_ref = create_mem_ref_raw (type, &parts); mem_ref = create_mem_ref_raw (type, &parts);
if (mem_ref) if (mem_ref)
......
...@@ -5510,6 +5510,7 @@ rewrite_use_address (struct ivopts_data *data, ...@@ -5510,6 +5510,7 @@ rewrite_use_address (struct ivopts_data *data,
{ {
aff_tree aff; aff_tree aff;
gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt); gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
tree base_hint = NULL_TREE;
tree ref; tree ref;
bool ok; bool ok;
...@@ -5517,7 +5518,22 @@ rewrite_use_address (struct ivopts_data *data, ...@@ -5517,7 +5518,22 @@ rewrite_use_address (struct ivopts_data *data,
gcc_assert (ok); gcc_assert (ok);
unshare_aff_combination (&aff); 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); copy_ref_info (ref, *use->op_p);
*use->op_p = ref; *use->op_p = ref;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment