Commit 820410e0 by Zdenek Dvorak Committed by Zdenek Dvorak

re PR tree-optimization/29516 (gfortran miscompiled)

	PR tree-optimization/29516
	* tree-ssa-address.c (tree_mem_ref_addr, add_to_parts,
	most_expensive_mult_to_index, addr_to_parts,
	create_mem_ref, maybe_fold_tmr): Make the type of
	fields of TARGET_MEM_REF sizetype.
	(move_fixed_address_to_symbol, move_pointer_to_base):
	New functions.
	* tree.def (TARGET_MEM_REF): Add comment on types of
	the operands.
	* gcc.dg/tree-ssa/loop-20.c: New test.

From-SVN: r120695
parent 2d3cb33a
2007-01-11 Zdenek Dvorak <dvorakz@suse.cz>
PR tree-optimization/29516
* tree-ssa-address.c (tree_mem_ref_addr, add_to_parts,
most_expensive_mult_to_index, addr_to_parts,
create_mem_ref, maybe_fold_tmr): Make the type of
fields of TARGET_MEM_REF sizetype.
(move_fixed_address_to_symbol, move_pointer_to_base):
New functions.
* tree.def (TARGET_MEM_REF): Add comment on types of
the operands.
* gcc.dg/tree-ssa/loop-20.c: New test.
2007-01-11 Joseph Myers <joseph@codesourcery.com>
* c-common.c (vector_types_convertible_p): Treat opaque types as
......
/* PR tree-optimization/29516 */
/* { dg-do compile { target fpic } } */
/* { dg-options "-O -ftree-vrp -fPIC -fdump-tree-ivopts" } */
typedef struct gfc_se { int pre; } gfc_se;
typedef struct gfc_ss_info { int dim[7]; } gfc_ss_info;
int gfc_rank_cst[7 + 1];
gfc_conv_array_transpose (gfc_se * se) {
int dest, src, dest_index, src_index;
gfc_ss_info *dest_info;
int n;
for (n = 0; n < 2; n++) {
dest_info->dim[n] = n;
src_index = gfc_rank_cst[1 - n];
a (se->pre, b (dest, dest_index), c (src, src_index));
}
}
/* Ivopts should not produce multiplication by a pointer constant. */
/* { dg-final { scan-tree-dump-times "\\* \[0-9\]*B;" 0 "ivopts" } } */
/* { dg-final { cleanup-tree-dump "ivopts" } } */
......@@ -244,54 +244,54 @@ addr_for_mem_ref (struct mem_address *addr, bool really_expand)
tree
tree_mem_ref_addr (tree type, tree mem_ref)
{
tree addr = NULL_TREE;
tree addr;
tree act_elem;
tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
tree addr_base = NULL_TREE, addr_off = NULL_TREE;
act_elem = TMR_INDEX (mem_ref);
if (act_elem)
if (sym)
addr_base = fold_convert (type, build_addr (sym, current_function_decl));
else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
{
act_elem = fold_convert (type, act_elem);
if (step)
act_elem = fold_build2 (MULT_EXPR, type, act_elem,
fold_convert (type, step));
addr = act_elem;
addr_base = fold_convert (type, base);
base = NULL_TREE;
}
act_elem = TMR_BASE (mem_ref);
act_elem = TMR_INDEX (mem_ref);
if (act_elem)
{
act_elem = fold_convert (type, act_elem);
if (addr)
addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
else
addr = act_elem;
if (step)
act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
addr_off = act_elem;
}
act_elem = TMR_SYMBOL (mem_ref);
act_elem = base;
if (act_elem)
{
act_elem = fold_convert (type, build_addr (act_elem,
current_function_decl));
if (addr)
addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
if (addr_off)
addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
else
addr = act_elem;
addr_off = act_elem;
}
if (offset && !integer_zerop (offset))
{
act_elem = fold_convert (type, offset);
if (addr)
addr = fold_build2 (PLUS_EXPR, type, addr, act_elem);
if (addr_off)
addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
else
addr = act_elem;
addr_off = offset;
}
if (!addr)
if (addr_off)
{
addr = fold_convert (type, addr_off);
if (addr_base)
addr = fold_build2 (PLUS_EXPR, type, addr_base, addr);
}
else if (addr_base)
addr = addr_base;
else
addr = build_int_cst (type, 0);
return addr;
......@@ -343,48 +343,91 @@ fixed_address_object_p (tree obj)
|| DECL_EXTERNAL (obj)));
}
/* Adds COEF * ELT to PARTS. TYPE is the type of the address we
construct. */
/* If ADDR contains an address of object that is a link time constant,
move it to PARTS->symbol. */
static void
add_to_parts (struct mem_address *parts, tree type, tree elt)
move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
{
tree elt_core = elt;
STRIP_NOPS (elt_core);
unsigned i;
tree val = NULL_TREE;
/* Check if this is a symbol. */
if (!parts->symbol
&& TREE_CODE (elt_core) == ADDR_EXPR
&& fixed_address_object_p (TREE_OPERAND (elt_core, 0)))
for (i = 0; i < addr->n; i++)
{
parts->symbol = TREE_OPERAND (elt_core, 0);
return;
if (!double_int_one_p (addr->elts[i].coef))
continue;
val = addr->elts[i].val;
if (TREE_CODE (val) == ADDR_EXPR
&& fixed_address_object_p (TREE_OPERAND (val, 0)))
break;
}
if (!parts->base)
{
parts->base = elt;
if (i == addr->n)
return;
parts->symbol = TREE_OPERAND (val, 0);
aff_combination_remove_elt (addr, i);
}
/* If ADDR contains an address of a dereferenced pointer, move it to
PARTS->base. */
static void
move_pointer_to_base (struct mem_address *parts, 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 (POINTER_TYPE_P (TREE_TYPE (val)))
break;
}
if (i == addr->n)
return;
parts->base = val;
aff_combination_remove_elt (addr, i);
}
/* Adds ELT to PARTS. */
static void
add_to_parts (struct mem_address *parts, tree elt)
{
tree type;
if (!parts->index)
{
parts->index = elt;
return;
}
if (!parts->base)
{
parts->base = elt;
return;
}
/* Add ELT to base. */
parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
type = TREE_TYPE (parts->base);
parts->base = fold_build2 (PLUS_EXPR, type,
parts->base,
fold_convert (type, elt));
}
/* Finds the most expensive multiplication in ADDR that can be
expressed in an addressing mode and move the corresponding
element(s) to PARTS. TYPE is the type of the address we
construct. */
element(s) to PARTS. */
static void
most_expensive_mult_to_index (struct mem_address *parts, tree type,
aff_tree *addr)
most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr)
{
HOST_WIDE_INT coef;
double_int best_mult, amult, amult_neg;
......@@ -435,18 +478,18 @@ most_expensive_mult_to_index (struct mem_address *parts, tree type,
continue;
}
elt = fold_convert (type, addr->elts[i].val);
elt = fold_convert (sizetype, addr->elts[i].val);
if (mult_elt)
mult_elt = fold_build2 (op_code, type, mult_elt, elt);
mult_elt = fold_build2 (op_code, sizetype, mult_elt, elt);
else if (op_code == PLUS_EXPR)
mult_elt = elt;
else
mult_elt = fold_build1 (NEGATE_EXPR, type, elt);
mult_elt = fold_build1 (NEGATE_EXPR, sizetype, elt);
}
addr->n = j;
parts->index = mult_elt;
parts->step = double_int_to_tree (type, best_mult);
parts->step = double_int_to_tree (sizetype, best_mult);
}
/* Splits address ADDR into PARTS.
......@@ -459,7 +502,7 @@ most_expensive_mult_to_index (struct mem_address *parts, tree type,
addressing modes is useless. */
static void
addr_to_parts (aff_tree *addr, tree type, struct mem_address *parts)
addr_to_parts (aff_tree *addr, struct mem_address *parts)
{
tree part;
unsigned i;
......@@ -470,25 +513,34 @@ addr_to_parts (aff_tree *addr, tree type, struct mem_address *parts)
parts->step = NULL_TREE;
if (!double_int_zero_p (addr->offset))
parts->offset = double_int_to_tree (type, addr->offset);
parts->offset = double_int_to_tree (sizetype, addr->offset);
else
parts->offset = NULL_TREE;
/* Try to find a symbol. */
move_fixed_address_to_symbol (parts, addr);
/* First move the most expensive feasible multiplication
to index. */
most_expensive_mult_to_index (parts, type, addr);
most_expensive_mult_to_index (parts, addr);
/* 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)
move_pointer_to_base (parts, addr);
/* Then try to process the remaining elements. */
for (i = 0; i < addr->n; i++)
{
part = fold_convert (type, addr->elts[i].val);
part = fold_convert (sizetype, addr->elts[i].val);
if (!double_int_one_p (addr->elts[i].coef))
part = fold_build2 (MULT_EXPR, type, part,
double_int_to_tree (type, addr->elts[i].coef));
add_to_parts (parts, type, part);
part = fold_build2 (MULT_EXPR, sizetype, part,
double_int_to_tree (sizetype, addr->elts[i].coef));
add_to_parts (parts, part);
}
if (addr->rest)
add_to_parts (parts, type, addr->rest);
add_to_parts (parts, fold_convert (sizetype, addr->rest));
}
/* Force the PARTS to register. */
......@@ -512,10 +564,10 @@ tree
create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
{
tree mem_ref, tmp;
tree addr_type = build_pointer_type (type);
tree addr_type = build_pointer_type (type), atype;
struct mem_address parts;
addr_to_parts (addr, addr_type, &parts);
addr_to_parts (addr, &parts);
gimplify_mem_ref_parts (bsi, &parts);
mem_ref = create_mem_ref_raw (type, &parts);
if (mem_ref)
......@@ -528,7 +580,7 @@ create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
/* Move the multiplication to index. */
gcc_assert (parts.index);
parts.index = force_gimple_operand_bsi (bsi,
build2 (MULT_EXPR, addr_type,
fold_build2 (MULT_EXPR, sizetype,
parts.index, parts.step),
true, NULL_TREE);
parts.step = NULL_TREE;
......@@ -540,15 +592,17 @@ create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
if (parts.symbol)
{
tmp = build_addr (parts.symbol, current_function_decl);
tmp = fold_convert (addr_type,
build_addr (parts.symbol, current_function_decl));
/* Add the symbol to base, eventually forcing it to register. */
if (parts.base)
{
if (parts.index)
parts.base = force_gimple_operand_bsi (bsi,
build2 (PLUS_EXPR, addr_type,
parts.base, tmp),
fold_build2 (PLUS_EXPR, addr_type,
fold_convert (addr_type, parts.base),
tmp),
true, NULL_TREE);
else
{
......@@ -565,18 +619,21 @@ create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
return mem_ref;
}
if (parts.index)
{
/* Add index to base. */
if (parts.base)
{
/* Add base to index. */
if (parts.index)
parts.index = force_gimple_operand_bsi (bsi,
build2 (PLUS_EXPR, addr_type,
atype = TREE_TYPE (parts.base);
parts.base = force_gimple_operand_bsi (bsi,
fold_build2 (PLUS_EXPR, atype,
parts.base,
parts.index),
fold_convert (atype, parts.index)),
true, NULL_TREE);
}
else
parts.index = parts.base;
parts.base = NULL_TREE;
parts.base = parts.index;
parts.index = NULL_TREE;
mem_ref = create_mem_ref_raw (type, &parts);
if (mem_ref)
......@@ -585,15 +642,18 @@ create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
if (parts.offset && !integer_zerop (parts.offset))
{
/* Try adding offset to index. */
if (parts.index)
parts.index = force_gimple_operand_bsi (bsi,
build2 (PLUS_EXPR, addr_type,
parts.index,
parts.offset),
/* Try adding offset to base. */
if (parts.base)
{
atype = TREE_TYPE (parts.base);
parts.base = force_gimple_operand_bsi (bsi,
fold_build2 (PLUS_EXPR, atype,
parts.base,
fold_convert (atype, parts.offset)),
true, NULL_TREE);
}
else
parts.index = parts.offset, bsi;
parts.base = parts.offset, bsi;
parts.offset = NULL_TREE;
......@@ -606,7 +666,7 @@ create_mem_ref (block_stmt_iterator *bsi, tree type, aff_tree *addr)
(only a register). If we cannot create such a memory reference,
something is really wrong. */
gcc_assert (parts.symbol == NULL_TREE);
gcc_assert (parts.base == NULL_TREE);
gcc_assert (parts.index == NULL_TREE);
gcc_assert (!parts.step || integer_onep (parts.step));
gcc_assert (!parts.offset || integer_zerop (parts.offset));
gcc_unreachable ();
......@@ -651,8 +711,9 @@ maybe_fold_tmr (tree ref)
if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
{
if (addr.offset)
addr.offset = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
addr.offset, addr.base);
addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
addr.offset,
fold_convert (sizetype, addr.base));
else
addr.offset = addr.base;
......@@ -665,14 +726,14 @@ maybe_fold_tmr (tree ref)
off = addr.index;
if (addr.step)
{
off = fold_binary_to_constant (MULT_EXPR, ptr_type_node,
off = fold_binary_to_constant (MULT_EXPR, sizetype,
off, addr.step);
addr.step = NULL_TREE;
}
if (addr.offset)
{
addr.offset = fold_binary_to_constant (PLUS_EXPR, ptr_type_node,
addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
addr.offset, off);
}
else
......
......@@ -938,6 +938,9 @@ DEFTREECODE (REALIGN_LOAD_EXPR, "realign_load", tcc_expression, 3)
SYMBOL + BASE + STEP * INDEX + OFFSET. Only variations and values valid on
the target are allowed.
The type of STEP, INDEX and OFFSET is sizetype. The type of BASE is
sizetype or a pointer type (if SYMBOL is NULL).
The sixth argument is the reference to the original memory access, which
is preserved for the purposes of the RTL alias analysis. The seventh
argument is a tag representing results of the tree level alias analysis. */
......
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