219 lines
7.8 KiB
Diff
219 lines
7.8 KiB
Diff
|
|
diff -uprN a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c 2020-05-26 21:03:43.132721856 +0800
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c 2020-05-19 20:12:32.655794652 +0800
|
||
|
|
@@ -9,4 +9,4 @@ unsigned test(unsigned k, unsigned b) {
|
||
|
|
return a[0]+a[1];
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */
|
||
|
|
+/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */
|
||
|
|
diff -uprN a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c 2020-05-26 21:03:43.132721856 +0800
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c 2020-05-19 20:12:32.667794652 +0800
|
||
|
|
@@ -11,4 +11,4 @@ unsigned test(unsigned k, unsigned b) {
|
||
|
|
return a[0]+a[1];
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */
|
||
|
|
+/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */
|
||
|
|
diff -uprN a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c 2020-05-26 21:03:43.132721856 +0800
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c 2020-05-19 20:12:32.667794652 +0800
|
||
|
|
@@ -13,4 +13,4 @@ int test(int b, int k) {
|
||
|
|
return a.data[0] + a.data[1];
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */
|
||
|
|
+/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */
|
||
|
|
diff -uprN a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
|
||
|
|
--- a/gcc/tree-ssa-phiopt.c 2020-05-26 21:03:43.132721856 +0800
|
||
|
|
+++ b/gcc/tree-ssa-phiopt.c 2020-05-26 21:02:02.872006469 +0800
|
||
|
|
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.
|
||
|
|
#include "params.h"
|
||
|
|
#include "case-cfn-macros.h"
|
||
|
|
#include "tree-eh.h"
|
||
|
|
+#include "inchash.h"
|
||
|
|
|
||
|
|
static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
|
||
|
|
static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
|
||
|
|
@@ -1984,6 +1985,18 @@ struct name_to_bb
|
||
|
|
basic_block bb;
|
||
|
|
};
|
||
|
|
|
||
|
|
+/* A hash-table of ARRAY_REF with a base of VAR_DECL and an offset of
|
||
|
|
+ SSA_NAME, and in which basic block it was seen, which would constitute
|
||
|
|
+ a no-trap region for same accessed. */
|
||
|
|
+struct array_ref_to_bb
|
||
|
|
+{
|
||
|
|
+ unsigned int ssa_name_ver;
|
||
|
|
+ unsigned int phase;
|
||
|
|
+ HOST_WIDE_INT size;
|
||
|
|
+ tree var_decl;
|
||
|
|
+ basic_block bb;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
/* Hashtable helpers. */
|
||
|
|
|
||
|
|
struct ssa_names_hasher : free_ptr_hash <name_to_bb>
|
||
|
|
@@ -1992,6 +2005,12 @@ struct ssa_names_hasher : free_ptr_hash
|
||
|
|
static inline bool equal (const name_to_bb *, const name_to_bb *);
|
||
|
|
};
|
||
|
|
|
||
|
|
+struct array_refs_hasher : free_ptr_hash <array_ref_to_bb>
|
||
|
|
+{
|
||
|
|
+ static inline hashval_t hash (const array_ref_to_bb *);
|
||
|
|
+ static inline bool equal (const array_ref_to_bb *, const array_ref_to_bb *);
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
/* Used for quick clearing of the hash-table when we see calls.
|
||
|
|
Hash entries with phase < nt_call_phase are invalid. */
|
||
|
|
static unsigned int nt_call_phase;
|
||
|
|
@@ -2005,6 +2024,16 @@ ssa_names_hasher::hash (const name_to_bb
|
||
|
|
^ (n->offset << 6) ^ (n->size << 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
+inline hashval_t
|
||
|
|
+array_refs_hasher::hash (const array_ref_to_bb *n)
|
||
|
|
+{
|
||
|
|
+ inchash::hash hstate (0);
|
||
|
|
+ hstate.add_int (n->ssa_name_ver);
|
||
|
|
+ hstate.add_hwi (n->size);
|
||
|
|
+ hstate.add_ptr (n->var_decl);
|
||
|
|
+ return hstate.end ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* The equality function of *P1 and *P2. */
|
||
|
|
|
||
|
|
inline bool
|
||
|
|
@@ -2016,11 +2045,21 @@ ssa_names_hasher::equal (const name_to_b
|
||
|
|
&& n1->size == n2->size;
|
||
|
|
}
|
||
|
|
|
||
|
|
+inline bool
|
||
|
|
+array_refs_hasher::equal (const array_ref_to_bb *n1, const array_ref_to_bb *n2)
|
||
|
|
+{
|
||
|
|
+ return n1->ssa_name_ver == n2->ssa_name_ver
|
||
|
|
+ && n1->size == n2->size
|
||
|
|
+ && n1->var_decl == n2->var_decl;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
class nontrapping_dom_walker : public dom_walker
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
nontrapping_dom_walker (cdi_direction direction, hash_set<tree> *ps)
|
||
|
|
- : dom_walker (direction), m_nontrapping (ps), m_seen_ssa_names (128) {}
|
||
|
|
+ : dom_walker (direction), m_nontrapping (ps),
|
||
|
|
+ m_seen_ssa_names (128), m_seen_array_refs (128)
|
||
|
|
+ {}
|
||
|
|
|
||
|
|
virtual edge before_dom_children (basic_block);
|
||
|
|
virtual void after_dom_children (basic_block);
|
||
|
|
@@ -2028,16 +2067,18 @@ public:
|
||
|
|
private:
|
||
|
|
|
||
|
|
/* We see the expression EXP in basic block BB. If it's an interesting
|
||
|
|
- expression (an MEM_REF through an SSA_NAME) possibly insert the
|
||
|
|
- expression into the set NONTRAP or the hash table of seen expressions.
|
||
|
|
- STORE is true if this expression is on the LHS, otherwise it's on
|
||
|
|
- the RHS. */
|
||
|
|
+ expression (an MEM_REF through an SSA_NAME or an ARRAY_REF with a base
|
||
|
|
+ of VAR_DECL and an offset of SSA_NAME) possibly insert the expression
|
||
|
|
+ into the set NONTRAP or the hash table of seen expressions. STORE
|
||
|
|
+ is true if this expression is on the LHS, otherwise it's on the RHS. */
|
||
|
|
void add_or_mark_expr (basic_block, tree, bool);
|
||
|
|
+ void add_or_mark_array_ref (basic_block, tree);
|
||
|
|
|
||
|
|
hash_set<tree> *m_nontrapping;
|
||
|
|
|
||
|
|
/* The hash table for remembering what we've seen. */
|
||
|
|
hash_table<ssa_names_hasher> m_seen_ssa_names;
|
||
|
|
+ hash_table<array_refs_hasher> m_seen_array_refs;
|
||
|
|
};
|
||
|
|
|
||
|
|
/* Called by walk_dominator_tree, when entering the block BB. */
|
||
|
|
@@ -2071,7 +2112,9 @@ nontrapping_dom_walker::before_dom_child
|
||
|
|
else if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt))
|
||
|
|
{
|
||
|
|
add_or_mark_expr (bb, gimple_assign_lhs (stmt), true);
|
||
|
|
+ add_or_mark_array_ref (bb, gimple_assign_lhs (stmt));
|
||
|
|
add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), false);
|
||
|
|
+ add_or_mark_array_ref (bb, gimple_assign_rhs1 (stmt));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
@@ -2148,6 +2191,74 @@ nontrapping_dom_walker::add_or_mark_expr
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* We see the expression EXP in basic block BB. If it's an interesting
|
||
|
|
+ expression (an ARRAY_REF with a base of VAR_DECL and an offset of
|
||
|
|
+ SSA_NAME) possibly insert the expression into the set NONTRAP or the
|
||
|
|
+ hash table of seen expressions. */
|
||
|
|
+void
|
||
|
|
+nontrapping_dom_walker::add_or_mark_array_ref (basic_block bb, tree exp)
|
||
|
|
+{
|
||
|
|
+ if (TREE_CODE (exp) == ARRAY_REF
|
||
|
|
+ && TREE_CODE (TREE_OPERAND (exp, 1)) == SSA_NAME
|
||
|
|
+ && int_size_in_bytes (TREE_TYPE (exp)) > 0)
|
||
|
|
+ {
|
||
|
|
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
|
||
|
|
+ tree base = get_base_address (exp);
|
||
|
|
+ /* if BASE is a local variable without address-taken, which can't be
|
||
|
|
+ read-only, a dominating load can constitute a no-trap region for
|
||
|
|
+ a store as well. */
|
||
|
|
+ if (TREE_CODE (base) == VAR_DECL
|
||
|
|
+ && auto_var_p (base) && !TREE_ADDRESSABLE (base))
|
||
|
|
+ {
|
||
|
|
+ struct array_ref_to_bb array_map;
|
||
|
|
+ basic_block found_array_bb = 0;
|
||
|
|
+
|
||
|
|
+ /* Try to find the last seen ARRAY_REF with the same base and
|
||
|
|
+ offset, which can trap. */
|
||
|
|
+ array_map.ssa_name_ver = SSA_NAME_VERSION (TREE_OPERAND (exp, 1));
|
||
|
|
+ array_map.phase = 0;
|
||
|
|
+ array_map.bb = 0;
|
||
|
|
+ array_map.size = size;
|
||
|
|
+ array_map.var_decl = base;
|
||
|
|
+
|
||
|
|
+ array_ref_to_bb **slot
|
||
|
|
+ = m_seen_array_refs.find_slot (&array_map, INSERT);
|
||
|
|
+ struct array_ref_to_bb *a2bb = *slot;
|
||
|
|
+ if (a2bb != NULL && a2bb->phase >= nt_call_phase)
|
||
|
|
+ {
|
||
|
|
+ found_array_bb = a2bb->bb;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* If we've found a trapping MEM_REF, _and_ it dominates EXP
|
||
|
|
+ (it's in a basic block on the path from us to the dominator root)
|
||
|
|
+ then we can't trap. */
|
||
|
|
+ if (found_array_bb && (((size_t)found_array_bb->aux) & 1) == 1)
|
||
|
|
+ {
|
||
|
|
+ m_nontrapping->add (exp);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ /* EXP might trap, so insert it into the hash table. */
|
||
|
|
+ if (a2bb != NULL)
|
||
|
|
+ {
|
||
|
|
+ a2bb->phase = nt_call_phase;
|
||
|
|
+ a2bb->bb = bb;
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ a2bb = XNEW (struct array_ref_to_bb);
|
||
|
|
+ a2bb->ssa_name_ver = SSA_NAME_VERSION (TREE_OPERAND (exp, 1));
|
||
|
|
+ a2bb->phase = nt_call_phase;
|
||
|
|
+ a2bb->bb = bb;
|
||
|
|
+ a2bb->size = size;
|
||
|
|
+ a2bb->var_decl = base;
|
||
|
|
+ *slot = a2bb;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* This is the entry point of gathering non trapping memory accesses.
|