aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-sccvn.c
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2014-11-24 14:07:18 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2014-11-24 14:07:18 +0000
commit8403c2cf5f66758fc78a01a675b0d218fded0202 (patch)
tree67f5be1ec46132969be310c870c5591ebbadbab2 /gcc/tree-ssa-sccvn.c
parent34a4625c52673828ff9b1eac7f68b5d23b58c5f5 (diff)
downloadgcc-8403c2cf5f66758fc78a01a675b0d218fded0202.zip
gcc-8403c2cf5f66758fc78a01a675b0d218fded0202.tar.gz
gcc-8403c2cf5f66758fc78a01a675b0d218fded0202.tar.bz2
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
Diffstat (limited to 'gcc/tree-ssa-sccvn.c')
-rw-r--r--gcc/tree-ssa-sccvn.c116
1 files changed, 95 insertions, 21 deletions
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index aa155a8..8b3f2c7 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -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;