aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/rtl-ssa/accesses.cc37
-rw-r--r--gcc/rtl-ssa/accesses.h3
-rw-r--r--gcc/rtl-ssa/internals.inl14
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr115928.c23
4 files changed, 55 insertions, 22 deletions
diff --git a/gcc/rtl-ssa/accesses.cc b/gcc/rtl-ssa/accesses.cc
index 3f1304f..5cc05cb 100644
--- a/gcc/rtl-ssa/accesses.cc
+++ b/gcc/rtl-ssa/accesses.cc
@@ -792,11 +792,11 @@ function_info::merge_clobber_groups (clobber_info *clobber1,
}
// GROUP spans INSN, and INSN now sets the resource that GROUP clobbers.
-// Split GROUP around INSN and return the clobber that comes immediately
-// before INSN.
+// Split GROUP around INSN, to form two new groups, and return the clobber
+// that comes immediately before INSN.
//
// The resource that GROUP clobbers is known to have an associated
-// splay tree.
+// splay tree. The caller must remove GROUP from the tree on return.
clobber_info *
function_info::split_clobber_group (clobber_group *group, insn_info *insn)
{
@@ -827,27 +827,20 @@ function_info::split_clobber_group (clobber_group *group, insn_info *insn)
prev = as_a<clobber_info *> (next->prev_def ());
}
- // Use GROUP to hold PREV and earlier clobbers. Create a new group for
- // NEXT onwards.
+ // Create a new group for each side of the split. We need to invalidate
+ // the old group so that clobber_info::group can tell whether a lazy
+ // update is needed.
+ clobber_info *first_clobber = group->first_clobber ();
clobber_info *last_clobber = group->last_clobber ();
- clobber_group *group1 = group;
- clobber_group *group2 = allocate<clobber_group> (next);
-
- // Finish setting up GROUP1, making sure that the roots and extremities
- // have a correct group pointer. Leave the rest to be updated lazily.
- group1->set_last_clobber (prev);
- tree1->set_group (group1);
- prev->set_group (group1);
-
- // Finish setting up GROUP2, with the same approach as for GROUP1.
- group2->set_first_clobber (next);
- group2->set_last_clobber (last_clobber);
- next->set_group (group2);
- tree2->set_group (group2);
- last_clobber->set_group (group2);
+ auto *group1 = allocate<clobber_group> (first_clobber, prev, tree1.root ());
+ auto *group2 = allocate<clobber_group> (next, last_clobber, tree2.root ());
// Insert GROUP2 into the splay tree as an immediate successor of GROUP1.
- def_splay_tree::insert_child (group1, 1, group2);
+ def_splay_tree::insert_child (group, 1, group2);
+ def_splay_tree::insert_child (group, 1, group1);
+
+ // Invalidate the old group.
+ group->set_last_clobber (nullptr);
return prev;
}
@@ -952,6 +945,8 @@ function_info::add_def (def_info *def)
}
prev = split_clobber_group (group, insn);
next = prev->next_def ();
+ tree.remove_root ();
+ last->set_splay_root (tree.root ());
}
// COMPARISON is < 0 if DEF comes before ROOT or > 0 if DEF comes
// after ROOT.
diff --git a/gcc/rtl-ssa/accesses.h b/gcc/rtl-ssa/accesses.h
index 7d2916d..27810a0 100644
--- a/gcc/rtl-ssa/accesses.h
+++ b/gcc/rtl-ssa/accesses.h
@@ -937,7 +937,8 @@ public:
void print (pretty_printer *pp) const;
private:
- clobber_group (clobber_info *clobber);
+ clobber_group (clobber_info *);
+ clobber_group (clobber_info *, clobber_info *, clobber_info *);
// Set the values of first_clobber () and last_clobber ().
void set_first_clobber (clobber_info *c) { m_clobber_or_set = c; }
diff --git a/gcc/rtl-ssa/internals.inl b/gcc/rtl-ssa/internals.inl
index c736877..9bc40bf 100644
--- a/gcc/rtl-ssa/internals.inl
+++ b/gcc/rtl-ssa/internals.inl
@@ -380,6 +380,20 @@ inline clobber_group::clobber_group (clobber_info *clobber)
clobber->m_group = this;
}
+// Construct a new group of clobber_infos that spans [FIRST_CLOBBER,
+// LAST_CLOBBER]. Set the root of the splay tree to CLOBBER_TREE.
+inline clobber_group::clobber_group (clobber_info *first_clobber,
+ clobber_info *last_clobber,
+ clobber_info *clobber_tree)
+ : def_node (first_clobber),
+ m_last_clobber (last_clobber),
+ m_clobber_tree (clobber_tree)
+{
+ first_clobber->m_group = this;
+ last_clobber->m_group = this;
+ clobber_tree->m_group = this;
+}
+
// Construct a node for the instruction with uid UID.
inline insn_info::order_node::order_node (int uid)
: insn_note (kind),
diff --git a/gcc/testsuite/gcc.dg/torture/pr115928.c b/gcc/testsuite/gcc.dg/torture/pr115928.c
new file mode 100644
index 0000000..4379fa9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr115928.c
@@ -0,0 +1,23 @@
+/* { dg-additional-options "-fgcse-sm" } */
+
+int a[1], b, c;
+struct {
+ int d;
+ int e;
+ int : 8;
+} f[1];
+static int g;
+char h, i, j;
+void k(int l) { b = 5 ^ a[b ^ (l & 5)]; }
+void m(long l) { k(c >> 6); }
+int main() {
+ g++;
+ if (b) {
+ h = 5 && j;
+ if (h)
+ h -= i;
+ m(f[g].d);
+ m(f[g].e);
+ }
+ return 0;
+}