Commit 8403c2cf by Richard Biener Committed by Richard Biener

re PR target/63679 ([AArch64] Failure to constant fold.)

2014-11-24  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/63679
	* tree-ssa-sccvn.c: Include ipa-ref.h, plugin-api.h and cgraph.h.
	(copy_reference_ops_from_ref): Fix non-constant ADDR_EXPR case
	to properly leave off at -1.
	(fully_constant_vn_reference_p): Generalize folding from
	constant initializers.
	(vn_reference_lookup_3): When looking through aggregate copies
	handle offsetted reads and try simplifying the result to
	a constant.
	* gimple-fold.h (fold_ctor_reference): Export.
	* gimple-fold.c (fold_ctor_reference): Likewise.

	* gcc.dg/tree-ssa/ssa-fre-42.c: New testcase.
	* gcc.dg/tree-ssa/20030807-5.c: Avoid folding read from global to zero.
	* gcc.target/i386/ssetype-1.c: Likewise.
	* gcc.target/i386/ssetype-3.c: Likewise.
	* gcc.target/i386/ssetype-5.c: Likewise.

From-SVN: r218019
parent 34a4625c
2014-11-24 Richard Biener <rguenther@suse.de>
PR tree-optimization/63679
* tree-ssa-sccvn.c: Include ipa-ref.h, plugin-api.h and cgraph.h.
(copy_reference_ops_from_ref): Fix non-constant ADDR_EXPR case
to properly leave off at -1.
(fully_constant_vn_reference_p): Generalize folding from
constant initializers.
(vn_reference_lookup_3): When looking through aggregate copies
handle offsetted reads and try simplifying the result to
a constant.
* gimple-fold.h (fold_ctor_reference): Export.
* gimple-fold.c (fold_ctor_reference): Likewise.
2014-11-24 Petr Murzin <petr.murzin@intel.com> 2014-11-24 Petr Murzin <petr.murzin@intel.com>
* simplify-rtx.c (simplify_ternary_operation): Simplify * simplify-rtx.c (simplify_ternary_operation): Simplify
...@@ -4788,10 +4788,6 @@ gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree)) ...@@ -4788,10 +4788,6 @@ gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree))
/* The following set of functions are supposed to fold references using /* The following set of functions are supposed to fold references using
their constant initializers. */ their constant initializers. */
static tree fold_ctor_reference (tree type, tree ctor,
unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT size, tree);
/* See if we can find constructor defining value of BASE. /* See if we can find constructor defining value of BASE.
When we know the consructor with constant offset (such as When we know the consructor with constant offset (such as
base is array[40] and we do know constructor of array), then base is array[40] and we do know constructor of array), then
...@@ -5027,7 +5023,7 @@ fold_nonarray_ctor_reference (tree type, tree ctor, ...@@ -5027,7 +5023,7 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
/* CTOR is value initializing memory, fold reference of type TYPE and size SIZE /* CTOR is value initializing memory, fold reference of type TYPE and size SIZE
to the memory at bit OFFSET. */ to the memory at bit OFFSET. */
static tree tree
fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT size, tree from_decl) unsigned HOST_WIDE_INT size, tree from_decl)
{ {
......
...@@ -39,6 +39,8 @@ extern tree follow_single_use_edges (tree); ...@@ -39,6 +39,8 @@ extern tree follow_single_use_edges (tree);
extern tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree), extern tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree),
tree (*) (tree) = no_follow_ssa_edges); tree (*) (tree) = no_follow_ssa_edges);
extern tree gimple_fold_stmt_to_constant (gimple, tree (*) (tree)); extern tree gimple_fold_stmt_to_constant (gimple, tree (*) (tree));
extern tree fold_ctor_reference (tree, tree, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, tree);
extern tree fold_const_aggregate_ref_1 (tree, tree (*) (tree)); extern tree fold_const_aggregate_ref_1 (tree, tree (*) (tree));
extern tree fold_const_aggregate_ref (tree); extern tree fold_const_aggregate_ref (tree);
extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree, extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree,
......
2014-11-24 Richard Biener <rguenther@suse.de>
PR tree-optimization/63679
* gcc.dg/tree-ssa/ssa-fre-42.c: New testcase.
* gcc.dg/tree-ssa/20030807-5.c: Avoid folding read from global to zero.
* gcc.target/i386/ssetype-1.c: Likewise.
* gcc.target/i386/ssetype-3.c: Likewise.
* gcc.target/i386/ssetype-5.c: Likewise.
2014-11-24 Jonathan Wakely <jwakely@redhat.com> 2014-11-24 Jonathan Wakely <jwakely@redhat.com>
Paolo Carlini <paolo.carlini@oracle.com> Paolo Carlini <paolo.carlini@oracle.com>
......
...@@ -13,7 +13,7 @@ struct rtx_def ...@@ -13,7 +13,7 @@ struct rtx_def
unsigned int unchanging:1; unsigned int unchanging:1;
}; };
static rtx current_sym_addr; rtx current_sym_addr;
int int
foo () foo ()
......
/* { dg-do run } */
/* { dg-require-alias "" } */
/* { dg-options "-O -fdump-tree-fre1" } */
extern void abort (void);
struct X { int a[128]; };
static const struct X a = { 0, 1, 2, 3 };
/* Prevent gimplify_modify_expr_rhs / gimplify_init_constructor from
expanding the aggregate copy below inline. */
static const struct X A __attribute__((alias("a")));
struct X *q;
int __attribute__((noinline))
foo ()
{
struct X b = A;
int *p = &b.a[2];
/* Prevent SRA from decomposing b. */
q = &b;
return *p;
}
int main()
{
if (foo() != 2)
abort ();
return 0;
}
/* Verify the aggregate copy we want to look through is still in place. */
/* { dg-final { scan-tree-dump "b = A;" "fre1" } } */
/* Verify we have propagated the element read all the way to the return. */
/* { dg-final { scan-tree-dump "return 2" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <xmmintrin.h> #include <xmmintrin.h>
static __m128d magic_a, magic_b; __m128d magic_a, magic_b;
__m128d __m128d
t1(void) t1(void)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <xmmintrin.h> #include <xmmintrin.h>
static __m128 magic_a, magic_b; __m128 magic_a, magic_b;
__m128 __m128
t1(void) t1(void)
{ {
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
/* Verify that we generate proper instruction with memory operand. */ /* Verify that we generate proper instruction with memory operand. */
#include <xmmintrin.h> #include <xmmintrin.h>
static __m128i magic_a, magic_b; __m128i magic_a, magic_b;
__m128i __m128i
t1(void) t1(void)
{ {
......
...@@ -65,6 +65,9 @@ along with GCC; see the file COPYING3. If not see ...@@ -65,6 +65,9 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-sccvn.h" #include "tree-ssa-sccvn.h"
#include "tree-cfg.h" #include "tree-cfg.h"
#include "domwalk.h" #include "domwalk.h"
#include "ipa-ref.h"
#include "plugin-api.h"
#include "cgraph.h"
/* This algorithm is based on the SCC algorithm presented by Keith /* This algorithm is based on the SCC algorithm presented by Keith
Cooper and L. Taylor Simpson in "SCC-Based Value numbering" Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
...@@ -920,7 +923,7 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result) ...@@ -920,7 +923,7 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
temp.op0 = ref; temp.op0 = ref;
break; break;
} }
/* Fallthrough. */ break;
/* These are only interesting for their operands, their /* These are only interesting for their operands, their
existence, and their type. They will never be the last existence, and their type. They will never be the last
ref in the chain of references (IE they require an ref in the chain of references (IE they require an
...@@ -1325,24 +1328,66 @@ fully_constant_vn_reference_p (vn_reference_t ref) ...@@ -1325,24 +1328,66 @@ fully_constant_vn_reference_p (vn_reference_t ref)
} }
} }
/* Simplify reads from constant strings. */ /* Simplify reads from constants or constant initializers. */
else if (op->opcode == ARRAY_REF else if (BITS_PER_UNIT == 8
&& TREE_CODE (op->op0) == INTEGER_CST && is_gimple_reg_type (ref->type)
&& integer_zerop (op->op1) && (!INTEGRAL_TYPE_P (ref->type)
&& operands.length () == 2) || TYPE_PRECISION (ref->type) % BITS_PER_UNIT == 0))
{ {
vn_reference_op_t arg0; HOST_WIDE_INT off = 0;
arg0 = &operands[1]; HOST_WIDE_INT size = tree_to_shwi (TYPE_SIZE (ref->type));
if (arg0->opcode == STRING_CST if (size % BITS_PER_UNIT != 0
&& (TYPE_MODE (op->type) || size > MAX_BITSIZE_MODE_ANY_MODE)
== TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0)))) return NULL_TREE;
&& GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT size /= BITS_PER_UNIT;
&& GET_MODE_SIZE (TYPE_MODE (op->type)) == 1 unsigned i;
&& tree_int_cst_sgn (op->op0) >= 0 for (i = 0; i < operands.length (); ++i)
&& compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0) {
return build_int_cst_type (op->type, if (operands[i].off == -1)
(TREE_STRING_POINTER (arg0->op0) return NULL_TREE;
[TREE_INT_CST_LOW (op->op0)])); off += operands[i].off;
if (operands[i].opcode == MEM_REF)
{
++i;
break;
}
}
vn_reference_op_t base = &operands[--i];
tree ctor = error_mark_node;
tree decl = NULL_TREE;
if (TREE_CODE_CLASS (base->opcode) == tcc_constant)
ctor = base->op0;
else if (base->opcode == MEM_REF
&& base[1].opcode == ADDR_EXPR
&& (TREE_CODE (TREE_OPERAND (base[1].op0, 0)) == VAR_DECL
|| TREE_CODE (TREE_OPERAND (base[1].op0, 0)) == CONST_DECL))
{
decl = TREE_OPERAND (base[1].op0, 0);
ctor = ctor_for_folding (decl);
}
if (ctor == NULL_TREE)
return build_zero_cst (ref->type);
else if (ctor != error_mark_node)
{
if (decl)
{
tree res = fold_ctor_reference (ref->type, ctor,
off * BITS_PER_UNIT,
size * BITS_PER_UNIT, decl);
if (res)
{
STRIP_USELESS_TYPE_CONVERSION (res);
if (is_gimple_min_invariant (res))
return res;
}
}
else
{
unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
if (native_encode_expr (ctor, buf, size, off) > 0)
return native_interpret_expr (ref->type, buf, size);
}
}
} }
return NULL_TREE; return NULL_TREE;
...@@ -1850,11 +1895,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, ...@@ -1850,11 +1895,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
may fail when comparing types for compatibility. But we really may fail when comparing types for compatibility. But we really
don't care here - further lookups with the rewritten operands don't care here - further lookups with the rewritten operands
will simply fail if we messed up types too badly. */ will simply fail if we messed up types too badly. */
HOST_WIDE_INT extra_off = 0;
if (j == 0 && i >= 0 if (j == 0 && i >= 0
&& lhs_ops[0].opcode == MEM_REF && lhs_ops[0].opcode == MEM_REF
&& lhs_ops[0].off != -1 && lhs_ops[0].off != -1)
&& (lhs_ops[0].off == vr->operands[i].off)) {
i--, j--; if (lhs_ops[0].off == vr->operands[i].off)
i--, j--;
else if (vr->operands[i].opcode == MEM_REF
&& vr->operands[i].off != -1)
{
extra_off = vr->operands[i].off - lhs_ops[0].off;
i--, j--;
}
}
/* i now points to the first additional op. /* i now points to the first additional op.
??? LHS may not be completely contained in VR, one or more ??? LHS may not be completely contained in VR, one or more
...@@ -1865,6 +1919,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, ...@@ -1865,6 +1919,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
/* Now re-write REF to be based on the rhs of the assignment. */ /* Now re-write REF to be based on the rhs of the assignment. */
copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs); copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
/* Apply an extra offset to the inner MEM_REF of the RHS. */
if (extra_off != 0)
{
if (rhs.length () < 2
|| rhs[0].opcode != MEM_REF
|| rhs[0].off == -1)
return (void *)-1;
rhs[0].off += extra_off;
rhs[0].op0 = int_const_binop (PLUS_EXPR, rhs[0].op0,
build_int_cst (TREE_TYPE (rhs[0].op0),
extra_off));
}
/* We need to pre-pend vr->operands[0..i] to rhs. */ /* We need to pre-pend vr->operands[0..i] to rhs. */
vec<vn_reference_op_s> old = vr->operands; vec<vn_reference_op_s> old = vr->operands;
if (i + 1 + rhs.length () > vr->operands.length ()) if (i + 1 + rhs.length () > vr->operands.length ())
...@@ -1882,6 +1950,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, ...@@ -1882,6 +1950,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
shared_lookup_references = vr->operands; shared_lookup_references = vr->operands;
vr->hashcode = vn_reference_compute_hash (vr); vr->hashcode = vn_reference_compute_hash (vr);
/* Try folding the new reference to a constant. */
tree val = fully_constant_vn_reference_p (vr);
if (val)
return vn_reference_lookup_or_insert_for_pieces
(vuse, vr->set, vr->type, vr->operands, val);
/* Adjust *ref from the new operands. */ /* Adjust *ref from the new operands. */
if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands)) if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
return (void *)-1; return (void *)-1;
......
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