[PR69123] fix VTA dataflow oscillation
Richard Biener
richard.guenther@gmail.com
Sat Jan 9 07:13:00 GMT 2016
On January 9, 2016 5:08:51 AM GMT+01:00, Alexandre Oliva <aoliva@redhat.com> wrote:
>Here are two patches related with PR69123, an infinite dataflow loop in
>VTA.
>
>The first non-comment hunk in var-tracking.c:drop_overlapping_mem_locs
>is what fixes the problem, but the other changes in the first patch fix
>similar problems that might cause other such oscillations.
>
>The second patch adds some more information to detailed vartrack dumps,
>avoiding short-circuiting of dataflow set compares and dumping added
>and
>removed locations for variables present in both sets.
>
>The patches are largely independent, but they were successfully
>regstrapped together on x86_64-linux-gnu and i686-linux-gnu. They were
>only compile-tested separately.
>
>Ok to install?
OK.
Thanks,
Richard.
>
>[PR69123] fix handling of MEMs in VTA to avoid dataflow oscillation
>
>From: Alexandre Oliva <aoliva@redhat.com>
>
>The problem arises because we used to drop overwritten MEMs from loc
>lists of VALUEs, but not of other onepart variables, and it just so
>happens that, by doing so, block 6 in the testcase has no D#5 in its
>output in the first pass, because the MEM holding its (previous) value
>was correctly dropped from value 88:88, but gains it in the second
>pass because D#5 has the MEM location incoming directly in its loc
>list, rather than indirectly in a VALUE.
>
>This incorrect binding enables other blocks to believe they have a
>tentative binding for D#5 in some cycles, but others, still operating
>on the early conclusion, believe there isn't, and they oscillate from
>that.
>
>Since we check for escaping MEMs in clobbers, we won't lose anything
>relevant by dropping call-clobbered or overwritten MEMs in all onepart
>variables, and this ensures the loc intersection operation in onepart
>vars won't let a MEM through that wasn't present in earlier
>iterations.
>
>for gcc/ChangeLog
>
> PR bootstrap/69123
> * var-tracking.c (drop_overlapping_mem_locs): Operate on all
> onepart vars. Fix typo in comment. Fix reversed condition in
> unshare test.
> (dataflow_set_remove_mem_locs): Operate on all onepart vars.
>
>for gcc/testsuite/ChangeLog
>
> PR bootstrap/69123
> * gcc.dg/pr69123.c: New.
>---
>gcc/testsuite/gcc.dg/pr69123.c | 95
>++++++++++++++++++++++++++++++++++++++++
> gcc/var-tracking.c | 12 +++--
> 2 files changed, 101 insertions(+), 6 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/pr69123.c
>
>diff --git a/gcc/testsuite/gcc.dg/pr69123.c
>b/gcc/testsuite/gcc.dg/pr69123.c
>new file mode 100644
>index 0000000..0546e20
>--- /dev/null
>+++ b/gcc/testsuite/gcc.dg/pr69123.c
>@@ -0,0 +1,95 @@
>+/* { dg-do compile } */
>+/* { dg-options "-O3 -g" } */
>+
>+/* This was reduced from gcc/tree-vect-slp.c by H.J.Lu. */
>+
>+struct xxx_def;
>+typedef xxx_def *xxx;
>+
>+union rtxxx
>+{
>+ const char *rt_str;
>+ xxx rt_xxx;
>+};
>+
>+struct xxx_def {
>+ union u {
>+ rtxxx fld[1];
>+ } u;
>+};
>+
>+extern xxx bar (void);
>+extern int foo1 (xxx);
>+
>+static inline xxx
>+foo2 (xxx arg0, xxx arg1)
>+{
>+ xxx rt;
>+ rt = bar ();
>+ (((rt)->u.fld[0]).rt_xxx) = arg0;
>+ (((rt)->u.fld[1]).rt_xxx) = arg1;
>+ return rt;
>+}
>+
>+static inline xxx
>+foo4 (const char *arg0 )
>+{
>+ xxx rt;
>+ rt = bar ();
>+ (((rt)->u.fld[0]).rt_str) = arg0;
>+ (((rt)->u.fld[1]).rt_xxx) = (xxx) 0;
>+ return rt;
>+}
>+
>+extern xxx foo5 (long);
>+
>+struct address_cost_data
>+{
>+ unsigned costs[2][2][2][2];
>+};
>+
>+void
>+get_address_cost (address_cost_data *data)
>+{
>+ unsigned acost;
>+ long i;
>+ long rat, off = 0;
>+ unsigned sym_p, var_p, off_p, rat_p;
>+ xxx addr, base;
>+ xxx reg0, reg1;
>+
>+ reg1 = bar ();
>+ addr = foo2 (reg1, (xxx) 0);
>+ rat = 1;
>+ acost = 0;
>+ reg0 = bar ();
>+ reg1 = bar ();
>+
>+ for (i = 0; i < 16; i++)
>+ {
>+ sym_p = i & 1;
>+ var_p = (i >> 1) & 1;
>+ off_p = (i >> 2) & 1;
>+ rat_p = (i >> 3) & 1;
>+
>+ addr = reg0;
>+ if (rat_p)
>+ addr = foo2 (addr, foo5 (rat)) ;
>+
>+ if (var_p)
>+ addr = foo2 (addr, reg1);
>+
>+ if (sym_p)
>+ base = foo4 ("");
>+ else if (off_p)
>+ base = foo5 (off);
>+ else
>+ base = (xxx) 0;
>+
>+ if (base)
>+ addr = foo2 (addr, base);
>+
>+ acost = foo1 (addr);
>+ data->costs[sym_p][var_p][off_p][rat_p] = acost;
>+ }
>+}
>diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
>index 634ebe0..a8931f3 100644
>--- a/gcc/var-tracking.c
>+++ b/gcc/var-tracking.c
>@@ -2224,7 +2224,7 @@ struct overlapping_mems
> };
>
> /* Remove all MEMs that overlap with COMS->LOC from the location list
>- of a hash table entry for a value. COMS->ADDR must be a
>+ of a hash table entry for a onepart variable. COMS->ADDR must be a
> canonicalized form of COMS->LOC's address, and COMS->LOC must be
> canonicalized itself. */
>
>@@ -2235,7 +2235,7 @@ drop_overlapping_mem_locs (variable **slot,
>overlapping_mems *coms)
> rtx mloc = coms->loc, addr = coms->addr;
> variable *var = *slot;
>
>- if (var->onepart == ONEPART_VALUE)
>+ if (var->onepart != NOT_ONEPART)
> {
> location_chain *loc, **locp;
> bool changed = false;
>@@ -4682,11 +4682,11 @@ dataflow_set_preserve_mem_locs (variable
>**slot, dataflow_set *set)
> {
> for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
> {
>- /* We want to remove dying MEMs that doesn't refer to DECL. */
>+ /* We want to remove dying MEMs that don't refer to DECL. */
> if (GET_CODE (loc->loc) == MEM
> && (MEM_EXPR (loc->loc) != decl
> || INT_MEM_OFFSET (loc->loc) != 0)
>- && !mem_dies_at_call (loc->loc))
>+ && mem_dies_at_call (loc->loc))
> break;
> /* We want to move here MEMs that do refer to DECL. */
> else if (GET_CODE (loc->loc) == VALUE
>@@ -4769,14 +4769,14 @@ dataflow_set_preserve_mem_locs (variable
>**slot, dataflow_set *set)
> }
>
> /* Remove all MEMs from the location list of a hash table entry for a
>- value. */
>+ onepart variable. */
>
> int
> dataflow_set_remove_mem_locs (variable **slot, dataflow_set *set)
> {
> variable *var = *slot;
>
>- if (var->onepart == ONEPART_VALUE)
>+ if (var->onepart != NOT_ONEPART)
> {
> location_chain *loc, **locp;
> bool changed = false;
>
>
>[PR69123] make dataflow_set_different details more verbose
>
>From: Alexandre Oliva <aoliva@redhat.com>
>
>for gcc/ChangeLog
>
> PR bootstrap/69123
> * var-tracking.c (dump_onepart_variable_differences): New.
> (dataflow_set_different): If a detailed dump is requested,
> delay early returns and dump differences between onepart
> variables present before and after, and added variables.
>---
>gcc/var-tracking.c | 113
>+++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 103 insertions(+), 10 deletions(-)
>
>diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
>index a5cca2b..634ebe0 100644
>--- a/gcc/var-tracking.c
>+++ b/gcc/var-tracking.c
>@@ -4921,6 +4921,63 @@ onepart_variable_different_p (variable *var1,
>variable *var2)
> return lc1 != lc2;
> }
>
>+/* Return true if one-part variables VAR1 and VAR2 are different.
>+ They must be in canonical order. */
>+
>+static void
>+dump_onepart_variable_differences (variable *var1, variable *var2)
>+{
>+ location_chain *lc1, *lc2;
>+
>+ gcc_assert (var1 != var2);
>+ gcc_assert (dump_file);
>+ gcc_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv));
>+ gcc_assert (var1->n_var_parts == 1
>+ && var2->n_var_parts == 1);
>+
>+ lc1 = var1->var_part[0].loc_chain;
>+ lc2 = var2->var_part[0].loc_chain;
>+
>+ gcc_assert (lc1 && lc2);
>+
>+ while (lc1 && lc2)
>+ {
>+ switch (loc_cmp (lc1->loc, lc2->loc))
>+ {
>+ case -1:
>+ fprintf (dump_file, "removed: ");
>+ print_rtl_single (dump_file, lc1->loc);
>+ lc1 = lc1->next;
>+ continue;
>+ case 0:
>+ break;
>+ case 1:
>+ fprintf (dump_file, "added: ");
>+ print_rtl_single (dump_file, lc2->loc);
>+ lc2 = lc2->next;
>+ continue;
>+ default:
>+ gcc_unreachable ();
>+ }
>+ lc1 = lc1->next;
>+ lc2 = lc2->next;
>+ }
>+
>+ while (lc1)
>+ {
>+ fprintf (dump_file, "removed: ");
>+ print_rtl_single (dump_file, lc1->loc);
>+ lc1 = lc1->next;
>+ }
>+
>+ while (lc2)
>+ {
>+ fprintf (dump_file, "added: ");
>+ print_rtl_single (dump_file, lc2->loc);
>+ lc2 = lc2->next;
>+ }
>+}
>+
> /* Return true if variables VAR1 and VAR2 are different. */
>
> static bool
>@@ -4964,19 +5021,32 @@ dataflow_set_different (dataflow_set *old_set,
>dataflow_set *new_set)
> {
> variable_iterator_type hi;
> variable *var1;
>+ bool diffound = false;
>+ bool details = (dump_file && (dump_flags & TDF_DETAILS));
>+
>+#define RETRUE \
>+ do \
>+ { \
>+ if (!details) \
>+ return true; \
>+ else \
>+ diffound = true; \
>+ } \
>+ while (0)
>
> if (old_set->vars == new_set->vars)
> return false;
>
> if (shared_hash_htab (old_set->vars)->elements ()
> != shared_hash_htab (new_set->vars)->elements ())
>- return true;
>+ RETRUE;
>
> FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (old_set->vars),
> var1, variable, hi)
> {
> variable_table_type *htab = shared_hash_htab (new_set->vars);
>variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash
>(var1->dv));
>+
> if (!var2)
> {
> if (dump_file && (dump_flags & TDF_DETAILS))
>@@ -4984,26 +5054,49 @@ dataflow_set_different (dataflow_set *old_set,
>dataflow_set *new_set)
> fprintf (dump_file, "dataflow difference found: removal of:\n");
> dump_var (var1);
> }
>- return true;
>+ RETRUE;
> }
>-
>- if (variable_different_p (var1, var2))
>+ else if (variable_different_p (var1, var2))
> {
>- if (dump_file && (dump_flags & TDF_DETAILS))
>+ if (details)
> {
> fprintf (dump_file, "dataflow difference found: "
> "old and new follow:\n");
> dump_var (var1);
>+ if (dv_onepart_p (var1->dv))
>+ dump_onepart_variable_differences (var1, var2);
> dump_var (var2);
> }
>- return true;
>+ RETRUE;
> }
> }
>
>- /* No need to traverse the second hashtab, if both have the same
>number
>- of elements and the second one had all entries found in the first
>one,
>- then it can't have any extra entries. */
>- return false;
>+ /* There's no need to traverse the second hashtab unless we want to
>+ print the details. If both have the same number of elements and
>+ the second one had all entries found in the first one, then the
>+ second can't have any extra entries. */
>+ if (!details)
>+ return diffound;
>+
>+ FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (new_set->vars),
>+ var1, variable, hi)
>+ {
>+ variable_table_type *htab = shared_hash_htab (old_set->vars);
>+ variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash
>(var1->dv));
>+ if (!var2)
>+ {
>+ if (details)
>+ {
>+ fprintf (dump_file, "dataflow difference found: addition
>of:\n");
>+ dump_var (var1);
>+ }
>+ RETRUE;
>+ }
>+ }
>+
>+#undef RETRUE
>+
>+ return diffound;
> }
>
> /* Free the contents of dataflow set SET. */
More information about the Gcc-patches
mailing list