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
This commit is contained in:
parent
34a4625c52
commit
8403c2cf5f
|
@ -1,3 +1,17 @@
|
|||
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>
|
||||
|
||||
* simplify-rtx.c (simplify_ternary_operation): Simplify
|
||||
|
|
|
@ -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
|
||||
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.
|
||||
When we know the consructor with constant offset (such as
|
||||
base is array[40] and we do know constructor of array), then
|
||||
|
@ -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
|
||||
to the memory at bit OFFSET. */
|
||||
|
||||
static tree
|
||||
tree
|
||||
fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
|
||||
unsigned HOST_WIDE_INT size, tree from_decl)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,8 @@ extern tree follow_single_use_edges (tree);
|
|||
extern tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree),
|
||||
tree (*) (tree) = no_follow_ssa_edges);
|
||||
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 (tree);
|
||||
extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree,
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
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>
|
||||
Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ struct rtx_def
|
|||
unsigned int unchanging:1;
|
||||
|
||||
};
|
||||
static rtx current_sym_addr;
|
||||
rtx current_sym_addr;
|
||||
|
||||
int
|
||||
foo ()
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* { 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 @@
|
|||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
static __m128d magic_a, magic_b;
|
||||
__m128d magic_a, magic_b;
|
||||
|
||||
__m128d
|
||||
t1(void)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
static __m128 magic_a, magic_b;
|
||||
__m128 magic_a, magic_b;
|
||||
__m128
|
||||
t1(void)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
/* Verify that we generate proper instruction with memory operand. */
|
||||
|
||||
#include <xmmintrin.h>
|
||||
static __m128i magic_a, magic_b;
|
||||
__m128i magic_a, magic_b;
|
||||
__m128i
|
||||
t1(void)
|
||||
{
|
||||
|
|
|
@ -65,6 +65,9 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "tree-ssa-sccvn.h"
|
||||
#include "tree-cfg.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
|
||||
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)
|
|||
temp.op0 = ref;
|
||||
break;
|
||||
}
|
||||
/* Fallthrough. */
|
||||
break;
|
||||
/* These are only interesting for their operands, their
|
||||
existence, and their type. They will never be the last
|
||||
ref in the chain of references (IE they require an
|
||||
|
@ -1325,24 +1328,66 @@ fully_constant_vn_reference_p (vn_reference_t ref)
|
|||
}
|
||||
}
|
||||
|
||||
/* Simplify reads from constant strings. */
|
||||
else if (op->opcode == ARRAY_REF
|
||||
&& TREE_CODE (op->op0) == INTEGER_CST
|
||||
&& integer_zerop (op->op1)
|
||||
&& operands.length () == 2)
|
||||
/* Simplify reads from constants or constant initializers. */
|
||||
else if (BITS_PER_UNIT == 8
|
||||
&& is_gimple_reg_type (ref->type)
|
||||
&& (!INTEGRAL_TYPE_P (ref->type)
|
||||
|| TYPE_PRECISION (ref->type) % BITS_PER_UNIT == 0))
|
||||
{
|
||||
vn_reference_op_t arg0;
|
||||
arg0 = &operands[1];
|
||||
if (arg0->opcode == STRING_CST
|
||||
&& (TYPE_MODE (op->type)
|
||||
== TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0))))
|
||||
&& GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT
|
||||
&& GET_MODE_SIZE (TYPE_MODE (op->type)) == 1
|
||||
&& tree_int_cst_sgn (op->op0) >= 0
|
||||
&& compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0)
|
||||
return build_int_cst_type (op->type,
|
||||
(TREE_STRING_POINTER (arg0->op0)
|
||||
[TREE_INT_CST_LOW (op->op0)]));
|
||||
HOST_WIDE_INT off = 0;
|
||||
HOST_WIDE_INT size = tree_to_shwi (TYPE_SIZE (ref->type));
|
||||
if (size % BITS_PER_UNIT != 0
|
||||
|| size > MAX_BITSIZE_MODE_ANY_MODE)
|
||||
return NULL_TREE;
|
||||
size /= BITS_PER_UNIT;
|
||||
unsigned i;
|
||||
for (i = 0; i < operands.length (); ++i)
|
||||
{
|
||||
if (operands[i].off == -1)
|
||||
return NULL_TREE;
|
||||
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;
|
||||
|
@ -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
|
||||
don't care here - further lookups with the rewritten operands
|
||||
will simply fail if we messed up types too badly. */
|
||||
HOST_WIDE_INT extra_off = 0;
|
||||
if (j == 0 && i >= 0
|
||||
&& lhs_ops[0].opcode == MEM_REF
|
||||
&& lhs_ops[0].off != -1
|
||||
&& (lhs_ops[0].off == vr->operands[i].off))
|
||||
i--, j--;
|
||||
&& lhs_ops[0].off != -1)
|
||||
{
|
||||
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.
|
||||
??? 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_,
|
|||
|
||||
/* Now re-write REF to be based on the rhs of the assignment. */
|
||||
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. */
|
||||
vec<vn_reference_op_s> old = vr->operands;
|
||||
if (i + 1 + rhs.length () > vr->operands.length ())
|
||||
|
@ -1882,6 +1950,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
|
|||
shared_lookup_references = vr->operands;
|
||||
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. */
|
||||
if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
|
||||
return (void *)-1;
|
||||
|
|
Loading…
Reference in New Issue