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:
parent
2b93f88dc5
commit
d7c0c068dd
@ -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
|
||||
|
@ -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
|
||||
|
29
gcc/testsuite/gcc.target/spu/ea/pr41857.c
Normal file
29
gcc/testsuite/gcc.target/spu/ea/pr41857.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user