This decouples the PRE reference IL from the VN hash tables, following
the corresponding PR103037 fix for nary expressions in r12-7389 to avoid
correctness issues regarding to access paths when inserting expressions.
Unfortunately this makes existing workarounds for alignment and alias
mismatches ineffective so those have to be re-implemented. Instead
of going back to implement canonexpr() during the ANTIC dataflow the
following does this at insertion time, hoping all relevant reaching
expressions will survive. A convenient place to do this is
sorted_array_from_bitmap_set, the actual magic worker is 'prefer',
for the moment handling alignment and innermost access size only,
as those are the cases we have test coverage. In particular the
access path difference seen in this PR is not covered - it is enough
to fix the AVAIL_OUT computation in compute_avail for this.
Where the old fixup code massaged the expressions the new code selects
from existing expressions or as fallback makes sure to not perform
code insertion when two incompatible expressions met.
Bootstrapped and tested on x86_64-unknown-linux-gnu. I've built a
set of applications looking for ICEs successfully, still I consider
this moderately risky at this point (but I'd also like to see
coverage rather than trying to hack the missing alias-set handling
in place without such coverage). I'll try to come up with a GIMPLE FE
testcase for this but it's also that the later we're putting this in
the worse (IMO), defering to stage1 and backporting will also not
really result in better coverage.
So what's your opinion?
OK for trunk?
Thanks,
Richard.
PR tree-optimization/122380
* tree-ssa-sscvn.h (copy_reference_ops_from_ref): Declare.
(vn_reference_compute_hash): Likewise.
(vn_reference_eq): Add parameter indicating lexical equivalence,
defaulted to false.
* tree-ssa-sccvn.cc (vn_reference_eq): Likewise.
(print_vn_reference_ops): Print alias type and alignment.
(vn_reference_compute_hash): Export.
(copy_reference_ops_from_ref): Likewise.
* tree-ssa-pre.cc (pre_expr_d::equal): Use lexical equivalence.
(get_or_alloc_expr_for_reference): Also get value-id, upon
zero assign a new value-id if the expression is unknown.
(expr_cmp): New helper.
(prefer): Likewise.
(pre_expr_DFS): Get expression exclusion bitmap and honor it.
(sorted_array_from_bitmap_set): If done for insertion, do limited
canonexpr() via pairwise prefer on expression pairs with the same
value, populating an exclution bitmap.
(phi_translate_1): Do not use the VN hashtable expressions
or insert there. Instead maintain a PRE view of expressions.
(clean): Adjust.
(do_hoist_insertion): Likewise.
(insert): Likewise.
(compute_avail): Use gimple_could_trap_p_1
on the original stmt rather than vn_reference_may_trap on
the VN leader. Use the original stmt operands for the PRE
view of reference expressions, only use the value number from the VN
tables. Remove no longer effective workarounds for semantically
different references with same value.
(fini_pre): Release operand vectors for PRE IL reference
expressions.
* g++.dg/torture/pr122380.C: New testcase.
* gcc.dg/torture/pr65270-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-pre-30.c: XFAIL.
---
gcc/testsuite/g++.dg/torture/pr122380.C | 40 +++
gcc/testsuite/gcc.dg/torture/pr65270-3.c | 24 ++
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c | 4 +-
gcc/tree-ssa-pre.cc | 372 +++++++++++++--------
gcc/tree-ssa-sccvn.cc | 47 ++-
gcc/tree-ssa-sccvn.h | 6 +-
6 files changed, 344 insertions(+), 149 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/torture/pr122380.C
create mode 100644 gcc/testsuite/gcc.dg/torture/pr65270-3.c
diff --git a/gcc/testsuite/g++.dg/torture/pr122380.C
b/gcc/testsuite/g++.dg/torture/pr122380.C
new file mode 100644
index 00000000000..da180978294
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr122380.C
@@ -0,0 +1,40 @@
+// { dg-do run }
+
+#include <variant>
+#include <vector>
+
+using A = std::vector <double>;
+using B = std::vector <int>;
+
+struct C
+{
+ bool c;
+ std::variant <A, B> d;
+};
+
+[[gnu::noipa, gnu::optimize ("assume-sane-operators-new-delete")]] bool
+foo (C *m, A *e)
+{
+ bool c = false;
+
+ if (m->c)
+ {
+ *e = std::move (std::get <A> (m->d));
+ c = true;
+ }
+ else
+ std::get <B> (m->d);
+
+ delete m;
+ return c;
+}
+
+int
+main ()
+{
+ A e { 1 };
+ C *m = new C;
+ m->c = true;
+ m->d = A { 1 };
+ foo (m, &e);
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr65270-3.c
b/gcc/testsuite/gcc.dg/torture/pr65270-3.c
new file mode 100644
index 00000000000..915fd94e5de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr65270-3.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+
+typedef int v4si_unaligned __attribute__((vector_size(16),aligned(4)));
+typedef int v4si __attribute__((vector_size(16)));
+
+v4si __attribute__((noipa))
+foo (bool aligned, bool write, int *p)
+{
+ if (write)
+ *(v4si_unaligned *)p = (v4si){ 0, 0, 0, 0 };
+ v4si tem;
+ if (aligned)
+ tem = *(v4si *)p;
+ else
+ tem = *(v4si_unaligned *)p;
+ return tem;
+}
+
+int a[8] __attribute__((aligned(4*sizeof(int))));
+int main()
+{
+ foo (false, false, &a[1]);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c
index 29dc1812338..0d15f90590a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c
@@ -24,5 +24,7 @@ bar (int b, int x)
/* We should see the partial redundant loads of f even though they
are using different types (of the same size). */
+/* XFAILed for dubious validity and PR122380 fix. The testcase did
+ not work with -fno-strict-aliasing. */
-/* { dg-final { scan-tree-dump-times "Replaced MEM" 3 "pre" } } */
+/* { dg-final { scan-tree-dump-times "Replaced MEM" 3 "pre" { xfail *-*-* } }
} */
diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc
index 6a5f1287fac..736076a5080 100644
--- a/gcc/tree-ssa-pre.cc
+++ b/gcc/tree-ssa-pre.cc
@@ -290,7 +290,7 @@ pre_expr_d::equal (const pre_expr_d *e1, const pre_expr_d
*e2)
return vn_nary_op_eq (PRE_EXPR_NARY (e1), PRE_EXPR_NARY (e2));
case REFERENCE:
return vn_reference_eq (PRE_EXPR_REFERENCE (e1),
- PRE_EXPR_REFERENCE (e2));
+ PRE_EXPR_REFERENCE (e2), true);
default:
gcc_unreachable ();
}
@@ -452,11 +452,17 @@ get_or_alloc_expr_for_nary (vn_nary_op_t nary, unsigned
value_id,
return result;
}
-/* Given an REFERENCE, get or create a pre_expr to represent it. */
+/* Given an REFERENCE, get or create a pre_expr to represent it. Assign
+ VALUE_ID to it or allocate a new value-id if it is zero. Record
+ LOC as the original location of the expression. If MOVE_OPERANDS
+ is true then ownership of REFERENCE->operands is transfered, otherwise
+ a copy is made if necessary. */
static pre_expr
get_or_alloc_expr_for_reference (vn_reference_t reference,
- location_t loc = UNKNOWN_LOCATION)
+ unsigned value_id,
+ location_t loc = UNKNOWN_LOCATION,
+ bool move_operands = false)
{
struct pre_expr_d expr;
pre_expr result;
@@ -467,13 +473,21 @@ get_or_alloc_expr_for_reference (vn_reference_t reference,
PRE_EXPR_REFERENCE (&expr) = reference;
result_id = lookup_expression_id (&expr);
if (result_id != 0)
- return expression_for_id (result_id);
+ {
+ if (move_operands)
+ reference->operands.release ();
+ return expression_for_id (result_id);
+ }
result = pre_expr_pool.allocate ();
result->kind = REFERENCE;
result->loc = loc;
- result->value_id = reference->value_id;
- PRE_EXPR_REFERENCE (result) = reference;
+ result->value_id = value_id ? value_id : get_next_value_id ();
+ vn_reference_t ref = XOBNEW (&pre_expr_obstack, struct vn_reference_s);
+ *ref = *reference;
+ if (!move_operands)
+ ref->operands = ref->operands.copy ();
+ PRE_EXPR_REFERENCE (result) = ref;
alloc_expression_id (result);
return result;
}
@@ -802,16 +816,95 @@ bitmap_set_free (bitmap_set_t set)
bitmap_clear (&set->values);
}
+
+/* Sort pre_expr after their value-id. */
+
+static int
+expr_cmp (const void *a_, const void *b_, void *)
+{
+ pre_expr a = *(pre_expr const *) a_;
+ pre_expr b = *(pre_expr const *) b_;
+ return a->value_id - b->value_id;
+}
+
+/* Return an expression that is a valid representation to insert for
+ both A and B reaching expressions. Return NULL if neither works,
+ in this case all expressions of the value will be elided. */
+
+static pre_expr
+prefer (pre_expr a, pre_expr b)
+{
+ if (a->kind == REFERENCE && b->kind == REFERENCE)
+ {
+ auto &oprsa = PRE_EXPR_REFERENCE (a)->operands;
+ auto &oprsb = PRE_EXPR_REFERENCE (b)->operands;
+ if (oprsa.length () > 1 && oprsb.length () > 1)
+ {
+ vn_reference_op_t vroa = &oprsa[oprsa.length () - 2];
+ vn_reference_op_t vrob = &oprsb[oprsb.length () - 2];
+ if (vroa->opcode == MEM_REF && vrob->opcode == MEM_REF)
+ {
+ pre_expr palign = NULL, psize = NULL;
+ /* We have to canonicalize to the more conservative alignment.
+ gcc.dg/torture/pr65270-?.c.*/
+ if (TYPE_ALIGN (vroa->type) < TYPE_ALIGN (vrob->type))
+ palign = a;
+ else if (TYPE_ALIGN (vroa->type) > TYPE_ALIGN (vrob->type))
+ palign = b;
+ /* We have to canonicalize to the more conservative (smaller)
+ innermost object access size. gcc.dg/torture/pr110799.c. */
+ if (TYPE_SIZE (vroa->type) != TYPE_SIZE (vrob->type))
+ {
+ if (!TYPE_SIZE (vroa->type))
+ psize = a;
+ else if (!TYPE_SIZE (vrob->type))
+ psize = b;
+ else if (TREE_CODE (TYPE_SIZE (vroa->type)) == INTEGER_CST
+ && TREE_CODE (TYPE_SIZE (vrob->type)) == INTEGER_CST)
+ {
+ int cmp = tree_int_cst_compare (TYPE_SIZE (vroa->type),
+ TYPE_SIZE (vrob->type));
+ if (cmp < 0)
+ psize = a;
+ else if (cmp > 0)
+ psize = b;
+ }
+ /* ??? What about non-constant sizes? */
+ }
+ if (palign && psize)
+ return NULL;
+ /* Note we cannot leave it undecided because when having
+ more than two expressions we have to keep doing
+ pariwise reduction. */
+ return palign ? palign : (psize ? psize : b);
+ }
+ }
+ }
+ /* Always prefer an non-REFERENCE, avoiding the above mess. */
+ else if (a->kind == REFERENCE)
+ return b;
+ else if (b->kind == REFERENCE)
+ return a;
+ else if (a->kind == b->kind)
+ ;
+ /* And prefer NAME over anything else. */
+ else if (b->kind == NAME)
+ return b;
+ else if (a->kind == NAME)
+ return a;
+ return b;
+}
+
static void
-pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap val_visited,
- vec<pre_expr> &post);
+pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap exclusions,
+ bitmap val_visited, vec<pre_expr> &post);
/* DFS walk leaders of VAL to their operands with leaders in SET, collecting
expressions in SET in postorder into POST. */
static void
-pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap val_visited,
- vec<pre_expr> &post)
+pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap exclusions,
+ bitmap val_visited, vec<pre_expr> &post)
{
unsigned int i;
bitmap_iterator bi;
@@ -822,21 +915,25 @@ pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap
val_visited,
if (!exprset->first->next)
{
EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
- if (bitmap_bit_p (&set->expressions, i))
- pre_expr_DFS (expression_for_id (i), set, val_visited, post);
+ if (bitmap_bit_p (&set->expressions, i)
+ && !bitmap_bit_p (exclusions, i))
+ pre_expr_DFS (expression_for_id (i), set, exclusions,
+ val_visited, post);
return;
}
EXECUTE_IF_AND_IN_BITMAP (exprset, &set->expressions, 0, i, bi)
- pre_expr_DFS (expression_for_id (i), set, val_visited, post);
+ if (!bitmap_bit_p (exclusions, i))
+ pre_expr_DFS (expression_for_id (i), set, exclusions,
+ val_visited, post);
}
/* DFS walk EXPR to its operands with leaders in SET, collecting
expressions in SET in postorder into POST. */
static void
-pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap val_visited,
- vec<pre_expr> &post)
+pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap exclusions,
+ bitmap val_visited, vec<pre_expr> &post)
{
switch (expr->kind)
{
@@ -852,7 +949,7 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap
val_visited,
recursed already. Avoid the costly bitmap_find_leader. */
if (bitmap_bit_p (&set->values, op_val_id)
&& bitmap_set_bit (val_visited, op_val_id))
- pre_expr_DFS (op_val_id, set, val_visited, post);
+ pre_expr_DFS (op_val_id, set, exclusions, val_visited, post);
}
break;
}
@@ -874,7 +971,7 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap
val_visited,
unsigned op_val_id = VN_INFO (op[n])->value_id;
if (bitmap_bit_p (&set->values, op_val_id)
&& bitmap_set_bit (val_visited, op_val_id))
- pre_expr_DFS (op_val_id, set, val_visited, post);
+ pre_expr_DFS (op_val_id, set, exclusions, val_visited, post);
}
}
break;
@@ -884,23 +981,71 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap
val_visited,
post.quick_push (expr);
}
-/* Generate an topological-ordered array of bitmap set SET. */
+/* Generate an topological-ordered array of bitmap set SET. If FOR_INSERTION
+ is true then perform canonexpr on the set. */
static vec<pre_expr>
-sorted_array_from_bitmap_set (bitmap_set_t set)
+sorted_array_from_bitmap_set (bitmap_set_t set, bool for_insertion)
{
unsigned int i;
bitmap_iterator bi;
vec<pre_expr> result;
/* Pre-allocate enough space for the array. */
- result.create (bitmap_count_bits (&set->expressions));
+ unsigned cnt = bitmap_count_bits (&set->expressions);
+ result.create (cnt);
+
+ /* For expressions with the same value from EXPRESSIONS retain only
+ expressions that can be inserted in place of all others. */
+ auto_bitmap exclusions;
+ bitmap_tree_view (exclusions);
+ if (for_insertion && cnt > 1)
+ {
+ EXECUTE_IF_SET_IN_BITMAP (&set->expressions, 0, i, bi)
+ result.safe_push (expression_for_id (i));
+ result.sort (expr_cmp, NULL);
+ for (unsigned i = 0; i < result.length () - 1; ++i)
+ if (result[i]->value_id == result[i+1]->value_id)
+ {
+ if (pre_expr p = prefer (result[i], result[i+1]))
+ {
+ /* We retain and iterate on exprs[i+1], if we want to
+ retain exprs[i], swap both. */
+ if (p == result[i])
+ std::swap (result[i], result[i+1]);
+ bitmap_set_bit (exclusions, get_expression_id (result[i]));
+ }
+ else
+ {
+ /* If neither works for pairwise chosing a conservative
+ alternative, drop all REFERENCE expressions for this value.
+ REFERENCE are always toplevel, so no chain should be
+ interrupted by pruning them. */
+ unsigned j, k;
+ for (j = i;; --j)
+ if (j == 0
+ || result[j - 1]->value_id != result[i]->value_id)
+ break;
+ for (k = j;; ++k)
+ {
+ if (k == result.length () - 1
+ || result[k + 1]->value_id != result[i]->value_id)
+ break;
+ if (result[k]->kind == REFERENCE)
+ bitmap_set_bit (exclusions,
+ get_expression_id (result[k]));
+ }
+ i = k;
+ }
+ }
+ result.truncate (0);
+ }
auto_bitmap val_visited (&grand_bitmap_obstack);
bitmap_tree_view (val_visited);
FOR_EACH_VALUE_ID_IN_SET (set, i, bi)
if (bitmap_set_bit (val_visited, i))
- pre_expr_DFS (i, set, val_visited, result);
+ pre_expr_DFS (i, set, exclusions, val_visited, result);
return result;
}
@@ -1589,8 +1734,6 @@ phi_translate_1 (bitmap_set_t dest,
newoperands.exists ()
? newoperands : operands,
&newref, VN_WALK);
- if (result)
- newoperands.release ();
/* We can always insert constants, so if we have a partial
redundant constant load of another type try to translate it
@@ -1605,7 +1748,10 @@ phi_translate_1 (bitmap_set_t dest,
tem = NULL_TREE;
}
if (tem)
- return get_or_alloc_expr_for_constant (tem);
+ {
+ newoperands.release ();
+ return get_or_alloc_expr_for_constant (tem);
+ }
}
/* If we'd have to convert things we would need to validate
@@ -1614,7 +1760,10 @@ phi_translate_1 (bitmap_set_t dest,
type in the VN tables either, as that would assert. */
if (result
&& !useless_type_conversion_p (ref->type, TREE_TYPE (result)))
- return NULL;
+ {
+ newoperands.release ();
+ return NULL;
+ }
else if (!result && newref
&& !useless_type_conversion_p (ref->type, newref->type))
{
@@ -1627,20 +1776,25 @@ phi_translate_1 (bitmap_set_t dest,
else
{
if (changed || !same_valid)
- new_val_id = get_next_value_id ();
+ new_val_id = 0;
else
new_val_id = ref->value_id;
- if (!newoperands.exists ())
- newoperands = operands.copy ();
- newref = vn_reference_insert_pieces (newvuse, ref->set,
- ref->base_set,
- ref->offset, ref->max_size,
- ref->type, newoperands,
- result, new_val_id);
- newoperands = vNULL;
}
- expr = get_or_alloc_expr_for_reference (newref, expr_loc);
- add_to_value (new_val_id, expr);
+ newref = XALLOCAVAR (struct vn_reference_s,
+ sizeof (vn_reference_s));
+ memcpy (newref, ref, sizeof (vn_reference_s));
+ newref->next = NULL;
+ newref->value_id = new_val_id;
+ newref->vuse = newvuse;
+ newref->operands
+ = newoperands.exists () ? newoperands : operands.copy ();
+ newoperands = vNULL;
+ newref->type = ref->type;
+ newref->result = result;
+ newref->hashcode = vn_reference_compute_hash (newref);
+ expr = get_or_alloc_expr_for_reference (newref, new_val_id,
+ expr_loc, true);
+ add_to_value (get_expr_value_id (expr), expr);
}
newoperands.release ();
return expr;
@@ -1946,7 +2100,7 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2,
pre_expr expr)
static void
clean (bitmap_set_t set1, bitmap_set_t set2 = NULL)
{
- vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1);
+ vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1, false);
pre_expr expr;
int i;
@@ -3694,7 +3848,7 @@ do_hoist_insertion (basic_block block)
hoistable_set.expressions = ANTIC_OUT->expressions;
/* Now finally construct the topological-ordered expression set. */
- vec<pre_expr> exprs = sorted_array_from_bitmap_set (&hoistable_set);
+ vec<pre_expr> exprs = sorted_array_from_bitmap_set (&hoistable_set, true);
/* If there are candidate values for hoisting, insert expressions
strategically to make the hoistable expressions fully redundant. */
@@ -3844,14 +3998,15 @@ insert (void)
if (flag_tree_pre && !single_pred_p (block))
{
vec<pre_expr> exprs
- = sorted_array_from_bitmap_set (ANTIC_IN (block));
+ = sorted_array_from_bitmap_set (ANTIC_IN (block), true);
/* Sorting is not perfect, iterate locally. */
while (do_pre_regular_insertion (block, dom, exprs))
;
exprs.release ();
if (do_partial_partial)
{
- exprs = sorted_array_from_bitmap_set (PA_IN (block));
+ exprs = sorted_array_from_bitmap_set (PA_IN (block),
+ true);
while (do_pre_partial_partial_insertion (block, dom,
exprs))
;
@@ -4089,7 +4244,7 @@ compute_avail (function *fun)
|| !vn_reference_may_trap (ref)))
{
result = get_or_alloc_expr_for_reference
- (ref, gimple_location (stmt));
+ (ref, ref->value_id, gimple_location (stmt));
add_to_value (get_expr_value_id (result), result);
bitmap_value_insert_into_set (EXP_GEN (block), result);
}
@@ -4141,6 +4296,11 @@ compute_avail (function *fun)
case VN_REFERENCE:
{
tree rhs1 = gimple_assign_rhs1 (stmt);
+ /* There is no point in trying to handle aggregates,
+ even when via punning we might get a value number
+ corresponding to a register typed load. */
+ if (!is_gimple_reg_type (TREE_TYPE (rhs1)))
+ continue;
ao_ref rhs1_ref;
ao_ref_init (&rhs1_ref, rhs1);
alias_set_type set = ao_ref_alias_set (&rhs1_ref);
@@ -4179,21 +4339,24 @@ compute_avail (function *fun)
vn_reference_lookup_pieces (gimple_vuse (stmt), set,
base_set, TREE_TYPE (rhs1),
operands, &ref, VN_WALK);
- if (!ref)
+ /* When there is no value recorded or the value was
+ recorded for a different type, fail, similar as
+ how we do during PHI translation. */
+ if (!ref
+ || !useless_type_conversion_p (TREE_TYPE (rhs1),
+ ref->type))
{
operands.release ();
continue;
}
+ operands.release ();
/* If the REFERENCE traps and there was a preceding
point in the block that might not return avoid
adding the reference to EXP_GEN. */
if (BB_MAY_NOTRETURN (block)
- && vn_reference_may_trap (ref))
- {
- operands.release ();
- continue;
- }
+ && gimple_could_trap_p_1 (stmt, true, false))
+ continue;
/* If the value of the reference is not invalidated in
this block until it is computed, add the expression
@@ -4217,103 +4380,29 @@ compute_avail (function *fun)
= SSA_NAME_DEF_STMT (gimple_vuse (def_stmt));
}
if (!ok)
- {
- operands.release ();
- continue;
- }
+ continue;
}
- /* If the load was value-numbered to another
- load make sure we do not use its expression
- for insertion if it wouldn't be a valid
- replacement. */
- /* At the momemt we have a testcase
- for hoist insertion of aligned vs. misaligned
- variants in gcc.dg/torture/pr65270-1.c thus
- with just alignment to be considered we can
- simply replace the expression in the hashtable
- with the most conservative one. */
- vn_reference_op_t ref1 = &ref->operands.last ();
- while (ref1->opcode != TARGET_MEM_REF
- && ref1->opcode != MEM_REF
- && ref1 != &ref->operands[0])
- --ref1;
- vn_reference_op_t ref2 = &operands.last ();
- while (ref2->opcode != TARGET_MEM_REF
- && ref2->opcode != MEM_REF
- && ref2 != &operands[0])
- --ref2;
- if ((ref1->opcode == TARGET_MEM_REF
- || ref1->opcode == MEM_REF)
- && (TYPE_ALIGN (ref1->type)
- > TYPE_ALIGN (ref2->type)))
- ref1->type
- = build_aligned_type (ref1->type,
- TYPE_ALIGN (ref2->type));
- /* TBAA behavior is an obvious part so make sure
- that the hashtable one covers this as well
- by adjusting the ref alias set and its base. */
- if ((ref->set == set
- || alias_set_subset_of (set, ref->set))
- && (ref->base_set == base_set
- || alias_set_subset_of (base_set, ref->base_set)))
- ;
- else if (ref1->opcode != ref2->opcode
- || (ref1->opcode != MEM_REF
- && ref1->opcode != TARGET_MEM_REF))
- {
- /* With mismatching base opcodes or bases
- other than MEM_REF or TARGET_MEM_REF we
- can't do any easy TBAA adjustment. */
- operands.release ();
- continue;
- }
- else if (ref->set == set
- || alias_set_subset_of (ref->set, set))
- {
- tree reft = reference_alias_ptr_type (rhs1);
- ref->set = set;
- ref->base_set = set;
- if (ref1->opcode == MEM_REF)
- ref1->op0
- = wide_int_to_tree (reft,
- wi::to_wide (ref1->op0));
- else
- ref1->op2
- = wide_int_to_tree (reft,
- wi::to_wide (ref1->op2));
- }
- else
- {
- ref->set = 0;
- ref->base_set = 0;
- if (ref1->opcode == MEM_REF)
- ref1->op0
- = wide_int_to_tree (ptr_type_node,
- wi::to_wide (ref1->op0));
- else
- ref1->op2
- = wide_int_to_tree (ptr_type_node,
- wi::to_wide (ref1->op2));
- }
- /* We also need to make sure that the access path
- ends in an access of the same size as otherwise
- we might assume an access may not trap while in
- fact it might. That's independent of whether
- TBAA is in effect. */
- if (TYPE_SIZE (ref1->type) != TYPE_SIZE (ref2->type)
- && (! TYPE_SIZE (ref1->type)
- || ! TYPE_SIZE (ref2->type)
- || ! operand_equal_p (TYPE_SIZE (ref1->type),
- TYPE_SIZE (ref2->type))))
- {
- operands.release ();
- continue;
- }
- operands.release ();
+ /* Record the un-valueized expression for EXP_GEN. */
+ copy_reference_ops_from_ref (rhs1, &operands);
+ vn_reference_t newref
+ = XALLOCAVAR (struct vn_reference_s,
+ sizeof (vn_reference_s));
+ memset (newref, 0, sizeof (vn_reference_s));
+ newref->value_id = ref->value_id;
+ newref->vuse = gimple_vuse (stmt);
+ newref->operands = operands;
+ newref->type = TREE_TYPE (rhs1);
+ newref->set = set;
+ newref->base_set = base_set;
+ newref->offset = 0;
+ newref->max_size = -1;
+ newref->result = ref->result;
+ newref->hashcode = vn_reference_compute_hash (newref);
result = get_or_alloc_expr_for_reference
- (ref, gimple_location (stmt));
+ (newref, newref->value_id,
+ gimple_location (stmt), true);
break;
}
@@ -4406,6 +4495,9 @@ fini_pre ()
{
value_expressions.release ();
constant_value_expressions.release ();
+ for (unsigned i = 1; i < expressions.length (); ++i)
+ if (expressions[i]->kind == REFERENCE)
+ PRE_EXPR_REFERENCE (expressions[i])->operands.release ();
expressions.release ();
bitmap_obstack_release (&grand_bitmap_obstack);
bitmap_set_pool.release ();
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 13deccb6c6b..6d668876264 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -280,12 +280,22 @@ print_vn_reference_ops (FILE *outfile, const
vec<vn_reference_op_s> ops)
closebrace = true;
}
}
+ if (vro->opcode == MEM_REF || vro->opcode == TARGET_MEM_REF)
+ fprintf (outfile, "(A%d)", TYPE_ALIGN (vro->type));
if (vro->op0 || vro->opcode == CALL_EXPR)
{
if (!vro->op0)
fprintf (outfile, internal_fn_name ((internal_fn)vro->clique));
else
- print_generic_expr (outfile, vro->op0);
+ {
+ if (vro->opcode == MEM_REF || vro->opcode == TARGET_MEM_REF)
+ {
+ fprintf (outfile, "(");
+ print_generic_expr (outfile, TREE_TYPE (vro->op0));
+ fprintf (outfile, ")");
+ }
+ print_generic_expr (outfile, vro->op0);
+ }
if (vro->op1)
{
fprintf (outfile, ",");
@@ -711,7 +721,7 @@ vn_reference_op_compute_hash (const vn_reference_op_t vro1,
inchash::hash &hstat
/* Compute a hash for the reference operation VR1 and return it. */
-static hashval_t
+hashval_t
vn_reference_compute_hash (const vn_reference_t vr1)
{
inchash::hash hstate;
@@ -764,10 +774,12 @@ vn_reference_compute_hash (const vn_reference_t vr1)
}
/* Return true if reference operations VR1 and VR2 are equivalent. This
- means they have the same set of operands and vuses. */
+ means they have the same set of operands and vuses. If LEXICAL
+ is true then the full access path has to be the same. */
bool
-vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const
vr2)
+vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const
vr2,
+ bool lexical)
{
unsigned i, j;
@@ -864,7 +876,7 @@ vn_reference_eq (const_vn_reference_t const vr1,
const_vn_reference_t const vr2)
else if (vro1->opcode == VIEW_CONVERT_EXPR && vro1->reverse)
return false;
reverse1 |= vro1->reverse;
- if (known_eq (vro1->off, -1))
+ if (lexical || known_eq (vro1->off, -1))
break;
off1 += vro1->off;
}
@@ -876,7 +888,7 @@ vn_reference_eq (const_vn_reference_t const vr1,
const_vn_reference_t const vr2)
else if (vro2->opcode == VIEW_CONVERT_EXPR && vro2->reverse)
return false;
reverse2 |= vro2->reverse;
- if (known_eq (vro2->off, -1))
+ if (lexical || known_eq (vro2->off, -1))
break;
off2 += vro2->off;
}
@@ -904,6 +916,27 @@ vn_reference_eq (const_vn_reference_t const vr1,
const_vn_reference_t const vr2)
return false;
if (!vn_reference_op_eq (vro1, vro2))
return false;
+ /* Both alignment and alias set are not relevant for the produced
+ value but need to be included when doing lexical comparison.
+ We also need to make sure that the access path ends in an
+ access of the same size as otherwise we might assume an access
+ may not trap while in fact it might. */
+ if (lexical
+ && (vro1->opcode == MEM_REF
+ || vro1->opcode == TARGET_MEM_REF)
+ && (TYPE_ALIGN (vro1->type) != TYPE_ALIGN (vro2->type)
+ || (TYPE_SIZE (vro1->type) != TYPE_SIZE (vro2->type)
+ && (! TYPE_SIZE (vro1->type)
+ || ! TYPE_SIZE (vro2->type)
+ || ! operand_equal_p (TYPE_SIZE (vro1->type),
+ TYPE_SIZE (vro2->type))))
+ || (get_deref_alias_set (vro1->opcode == MEM_REF
+ ? TREE_TYPE (vro1->op0)
+ : TREE_TYPE (vro1->op2))
+ != get_deref_alias_set (vro1->opcode == MEM_REF
+ ? TREE_TYPE (vro2->op0)
+ : TREE_TYPE (vro2->op2)))))
+ return false;
++j;
++i;
}
@@ -916,7 +949,7 @@ vn_reference_eq (const_vn_reference_t const vr1,
const_vn_reference_t const vr2)
/* Copy the operations present in load/store REF into RESULT, a vector of
vn_reference_op_s's. */
-static void
+void
copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
{
/* For non-calls, store the information that makes up the address. */
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 6bf08027641..d175cff7b36 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -274,13 +274,17 @@ vn_reference_t vn_reference_insert_pieces (tree,
alias_set_type, alias_set_type,
poly_int64, poly_int64,
tree, vec<vn_reference_op_s>,
tree, unsigned int);
+void copy_reference_ops_from_ref (tree, vec<vn_reference_op_s> *);
+hashval_t vn_reference_compute_hash (const vn_reference_t vr1);
+
void print_vn_reference_ops (FILE *, const vec<vn_reference_op_s>);
bool vn_nary_op_eq (const_vn_nary_op_t const vno1,
const_vn_nary_op_t const vno2);
bool vn_nary_may_trap (vn_nary_op_t);
bool vn_reference_may_trap (vn_reference_t);
-bool vn_reference_eq (const_vn_reference_t const, const_vn_reference_t const);
+bool vn_reference_eq (const_vn_reference_t const, const_vn_reference_t const,
+ bool = false);
unsigned int get_max_value_id (void);
unsigned int get_max_constant_value_id (void);
--
2.51.0