Bug 69728 - [7 Regression] internal compiler error: in outer_projection_mupa, at graphite-sese-to-poly.c:1175
Summary: [7 Regression] internal compiler error: in outer_projection_mupa, at graphite...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 6.0
: P4 normal
Target Milestone: 8.0
Assignee: Richard Biener
URL:
Keywords: ice-on-valid-code
: 80069 80105 81226 82057 (view as bug list)
Depends on:
Blocks: graphite 80069 80105
  Show dependency treegraph
 
Reported: 2016-02-09 09:25 UTC by ktkachov
Modified: 2019-11-15 03:06 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work: 5.3.1, 8.0
Known to fail: 6.0, 7.2.0, 7.5.0
Last reconfirmed: 2017-02-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ktkachov 2016-02-09 09:25:39 UTC
The following testcase ICEs for me on aarch64 with -O3 -floop-interchange.

int a[1];
int b, c, d, e;
void
fn1 ()
{
  d = 9;
  for (; c; c++)
    {
      ++d;
      b = 8;
      for (; b; b--)
        {
          if (d)
            break;
          a[b] = e;
        }
    }
}

mycrash.c:4:1: internal compiler error: in outer_projection_mupa, at graphite-sese-to-poly.c:1175
 fn1 ()
 ^~~
0x1068f68 outer_projection_mupa
        $SRC/gcc/graphite-sese-to-poly.c:1175
0x1068f68 add_loop_schedule
        $SRC/gcc/graphite-sese-to-poly.c:1223
0x106af92 build_schedule_loop
        $SRC/gcc/graphite-sese-to-poly.c:1263
0x106aeae build_schedule_loop_nest
        $SRC/gcc/graphite-sese-to-poly.c:1319
0x106af71 build_schedule_loop
        $SRC/gcc/graphite-sese-to-poly.c:1257
0x106aeae build_schedule_loop_nest
        $SRC/gcc/graphite-sese-to-poly.c:1319
0x106bd2f build_original_schedule
        $SRC/gcc/graphite-sese-to-poly.c:1337
0x106bd2f build_poly_scop(scop*)
        $SRC/gcc/graphite-sese-to-poly.c:1368
0x105582c graphite_transform_loops()
        $SRC/gcc/graphite.c:319
0x10559a4 graphite_transforms
        $SRC/gcc/graphite.c:356
0x10559a4 execute
        $SRC/gcc/graphite.c:433
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.


This is with ISL 0.15
Comment 1 Tom de Vries 2016-03-15 11:20:11 UTC
Confirmed on x86_64.
Comment 2 Tom de Vries 2016-04-12 10:12:33 UTC
For two more testcases: PR68756 comment 3
Comment 3 Jakub Jelinek 2016-04-27 10:58:08 UTC
GCC 6.1 has been released.
Comment 4 Richard Biener 2016-08-22 08:24:50 UTC
GCC 6.2 is being released, adjusting target milestone.
Comment 5 Richard Biener 2016-08-22 08:25:54 UTC
GCC 6.2 is being released, adjusting target milestone.
Comment 6 Jakub Jelinek 2016-12-21 10:58:20 UTC
GCC 6.3 is being released, adjusting target milestone.
Comment 7 Richard Biener 2017-02-08 15:00:16 UTC
Reconfirmed on trunk.
Comment 8 Richard Biener 2017-02-09 11:57:17 UTC
removing the assert doesn't fix it (ISL complains).  This is all ISL stuff I don't understand, somebody else needs to look at this - the SCOP is quite regular.
Confirmed with ISL 0.18.
Comment 9 Richard Biener 2017-07-04 08:49:12 UTC
GCC 6.4 is being released, adjusting target milestone.
Comment 10 Martin Liška 2017-09-11 07:56:44 UTC
*** Bug 80069 has been marked as a duplicate of this bug. ***
Comment 11 Martin Liška 2017-09-11 07:58:10 UTC
*** Bug 81226 has been marked as a duplicate of this bug. ***
Comment 12 Martin Liška 2017-09-11 07:58:21 UTC
*** Bug 82057 has been marked as a duplicate of this bug. ***
Comment 13 Richard Biener 2017-09-18 13:01:15 UTC
A "simple" patch like the following seems to "work".

Index: gcc/graphite-sese-to-poly.c
===================================================================
--- gcc/graphite-sese-to-poly.c (revision 252920)
+++ gcc/graphite-sese-to-poly.c (working copy)
@@ -1043,6 +1043,13 @@ add_loop_schedule (__isl_take isl_schedu
   if (empty < 0 || empty)
     return empty < 0 ? isl_schedule_free (schedule) : schedule;
 
+  isl_union_set *domain = isl_schedule_get_domain (schedule);
+  if (isl_union_set_is_empty (domain))
+    {
+      isl_union_set_free (domain);
+      return schedule;
+    }
+
   isl_space *space = isl_set_get_space (iterators);
   int loop_index = isl_space_dim (space, isl_dim_set) - 1;
 
@@ -1063,7 +1070,6 @@ add_loop_schedule (__isl_take isl_schedu
   prefix = isl_multi_aff_set_tuple_id (prefix, isl_dim_out, label);
 
   int n = isl_multi_aff_dim (prefix, isl_dim_in);
-  isl_union_set *domain = isl_schedule_get_domain (schedule);
   isl_multi_union_pw_aff *mupa = outer_projection_mupa (domain, n);
   mupa = isl_multi_union_pw_aff_apply_multi_aff (mupa, prefix);
   return isl_schedule_insert_partial_schedule (schedule, mupa);


but it results in a bougs initial schedule:

[scheduler] original ast:
{
  for (int c0 = 0; c0 < -P_21; c0 += 1) {
    S_9(c0);
    if (P_21 + c0 <= -2)
      S_8(c0);
  }
  S_10();
}

so the conditional loop ended up not being a loop.  I believe in this
case we are somehow confused by 'c' wrapping?  niter is computed
as -(unsigned int) (c.7_21 + 1).  Can we really "handle" negating
an unsigned value?

static isl_pw_aff *
extract_affine (scop_p s, tree e, __isl_take isl_space *space)
{
..
    case NEGATE_EXPR:
    case BIT_NOT_EXPR:
      lhs = extract_affine (s, TREE_OPERAND (e, 0), isl_space_copy (space));
      rhs = extract_affine (s, integer_minus_one_node, space);
      res = isl_pw_aff_mul (lhs, rhs);
      break;

so we do x * -1 for negate -- that looks ok.  At least bogus for
BIT_NOT_EXPR which is really -1 - x, not x * -1.

Doesn't seem to handle any conversion to signed correctly either as it
misses an appropriate 'wrap' operation (the existing one only works
for unsigned).  The offset argument in POINTER_PLUS_EXPR handling needs
to be interpreted as signed.

So for the ICE I now have the hackish

Index: gcc/graphite-sese-to-poly.c
===================================================================
--- gcc/graphite-sese-to-poly.c (revision 252920)
+++ gcc/graphite-sese-to-poly.c (working copy)
@@ -1030,6 +1035,8 @@ outer_projection_mupa (__isl_take isl_un
   return isl_multi_union_pw_aff_from_union_pw_multi_aff (data.res);
 }
 
+static bool schedule_error;
+
 /* Embed SCHEDULE in the constraints of the LOOP domain.  */
 
 static isl_schedule *
@@ -1043,6 +1050,14 @@ add_loop_schedule (__isl_take isl_schedu
   if (empty < 0 || empty)
     return empty < 0 ? isl_schedule_free (schedule) : schedule;
 
+  isl_union_set *domain = isl_schedule_get_domain (schedule);
+  if (isl_union_set_is_empty (domain))
+    {
+      schedule_error = true;
+      isl_union_set_free (domain);
+      return schedule;
+    }
+
   isl_space *space = isl_set_get_space (iterators);
   int loop_index = isl_space_dim (space, isl_dim_set) - 1;
 
@@ -1169,6 +1183,8 @@ build_schedule_loop_nest (scop_p scop, i
 static bool
 build_original_schedule (scop_p scop)
 {
+  schedule_error = false;
+
   int i = 0;
   int n = scop->pbbs.length ();
   while (i < n)
@@ -1183,6 +1199,14 @@ build_original_schedule (scop_p scop)
       scop->original_schedule = add_in_sequence (scop->original_schedule, s);
     }
 
+  if (schedule_error)
+    {
+      if (dump_file)
+       fprintf (dump_file, "[sese-to-poly] failed to build "
+                "original schedule\n");
+      return false;
+    }
+
   if (dump_file)
     {
       fprintf (dump_file, "[sese-to-poly] original schedule:\n");
Comment 14 Richard Biener 2017-09-18 13:20:11 UTC
*** Bug 80105 has been marked as a duplicate of this bug. ***
Comment 15 Sebastian Pop 2017-09-18 13:36:15 UTC
It makes sense to early fail when the schedule builder gets confused and built an empty domain.  Could you please also add a comment around the if that sets schedule_error?  The change looks good.  Thanks.
Comment 16 Richard Biener 2017-09-19 08:22:30 UTC
(In reply to Richard Biener from comment #13)
> A "simple" patch like the following seems to "work".
> 
> Index: gcc/graphite-sese-to-poly.c
> ===================================================================
> --- gcc/graphite-sese-to-poly.c (revision 252920)
> +++ gcc/graphite-sese-to-poly.c (working copy)
> @@ -1043,6 +1043,13 @@ add_loop_schedule (__isl_take isl_schedu
>    if (empty < 0 || empty)
>      return empty < 0 ? isl_schedule_free (schedule) : schedule;
>  
> +  isl_union_set *domain = isl_schedule_get_domain (schedule);
> +  if (isl_union_set_is_empty (domain))
> +    {
> +      isl_union_set_free (domain);
> +      return schedule;
> +    }
> +
>    isl_space *space = isl_set_get_space (iterators);
>    int loop_index = isl_space_dim (space, isl_dim_set) - 1;
>  
> @@ -1063,7 +1070,6 @@ add_loop_schedule (__isl_take isl_schedu
>    prefix = isl_multi_aff_set_tuple_id (prefix, isl_dim_out, label);
>  
>    int n = isl_multi_aff_dim (prefix, isl_dim_in);
> -  isl_union_set *domain = isl_schedule_get_domain (schedule);
>    isl_multi_union_pw_aff *mupa = outer_projection_mupa (domain, n);
>    mupa = isl_multi_union_pw_aff_apply_multi_aff (mupa, prefix);
>    return isl_schedule_insert_partial_schedule (schedule, mupa);
> 
> 
> but it results in a bougs initial schedule:
> 
> [scheduler] original ast:
> {
>   for (int c0 = 0; c0 < -P_21; c0 += 1) {
>     S_9(c0);
>     if (P_21 + c0 <= -2)
>       S_8(c0);
>   }
>   S_10();
> }
> 
> so the conditional loop ended up not being a loop.  I believe in this
> case we are somehow confused by 'c' wrapping?  niter is computed
> as -(unsigned int) (c.7_21 + 1).  Can we really "handle" negating
> an unsigned value?

The real issue is that we probably mishandle the constraint generation for
-(unsigned int) (c.7_21 + 1) (niter of the loop) or that ISL mis-handles
them.  I can't fully decipher the details in the dump but I see

[sese-to-poly] adding constraint to the domain: [P_21] -> { [i1] : i1 <= 2147483637 }
[sese-to-poly] set pbb_9->domain: [P_21] -> { [i1] : -2147483648 <= P_21 <= 2147483647 and 0 <= i1 <= 2147483637 and 4294967296*floor((-1 - P_21)/4294967296) < -P_21 - i1 }
[sese-to-poly] set pbb_8->domain: [P_21] -> { [i1] : -2147483648 <= P_21 <= 2147483647 and 0 <= i1 <= 2147483637 and 4294967296*floor((-1 - P_21)/4294967296) < -P_21 - i1 }
[sese-to-poly] adding one extra dimension to the domain for loop_2.
[sese-to-poly] adding constraint to the domain: [P_21] -> { [i1, i2] : i2 >= 0 }
[sese-to-poly] set pbb_6->domain: [P_21] -> { [i1, i2] : -2147483648 <= P_21 <= 2147483647 and 0 <= i1 <= 2147483637 and 0 <= i2 <= 7 and 4294967296*floor((-1 - P_21)/4294967296) < -P_21 - i1 }
[sese-to-poly] set pbb_10->domain: [P_21] -> { [] : -2147483648 <= P_21 <= 2147483647 and 4294967296*floor((-1 - P_21)/4294967296) >= -2147483638 - P_21 }

where I believe the pbb_6 domain is the issue.  The constraint on P_21

4294967296*floor((-1 - P_21)/4294967296) < -P_21 - i1

where I assume P_21 is c.7_12, is supposed to capture th case
where c initially is negative and increasing until it is zero,
the case where it is initially positive would invoke undefined behavior.
But we have 0 <= i1 <= 2147483637, whereever that comes from.  Probably
from the i1 <= 2147483637 constraint?

That said, this testcase is somewhat confusing....

Still, if ISL can get "confused" does it reliably return an empty domain?

That is, aren't we papering over possible wrong-code issues in GRAPHITE
or ISL with handling this as error?  Couldn't it be GCC simply didn't
optimize the code properly and the domain can really be empty in which
case we should not schedule any stmts of the loop?  W/o setting the
error in the patch we end up scheduling the stmt anyway which would
be wrong.  So how'd we properly handle a valid empty domain?  The
initial schedule generation is somewhat of a mess to me...

Anyway, I added

  /* We cannot apply an empty domain to pbbs in this loop so fail.
     ???  Somehow drop pbbs in the loop instead.  */

and committed the patch (we clearly cannot properly handle an empty
domain during initial schedule generation even if the empty domain
is correct).
Comment 17 Richard Biener 2017-09-19 08:25:27 UTC
Fixed.
Comment 18 Richard Biener 2017-09-19 08:25:49 UTC
Author: rguenth
Date: Tue Sep 19 08:25:17 2017
New Revision: 252968

URL: https://gcc.gnu.org/viewcvs?rev=252968&root=gcc&view=rev
Log:
2017-09-19  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/69728
	* graphite-sese-to-poly.c (schedule_error): New global.
	(add_loop_schedule): Handle empty domain by failing the
	schedule.
	(build_original_schedule): Handle schedule_error.

	* gfortran.dg/graphite/pr69728.f90: New testcase.
	* gcc.dg/graphite/pr69728.c: Likewise.

Added:
    trunk/gcc/testsuite/gcc.dg/graphite/pr69728.c
    trunk/gcc/testsuite/gfortran.dg/graphite/pr69728.f90
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/graphite-sese-to-poly.c
    trunk/gcc/testsuite/ChangeLog
Comment 19 Sebastian Pop 2017-09-19 14:31:18 UTC
> So how'd we properly handle a valid empty domain?

DCE the statement.

If the domain for a statement is empty, it means that the statement does not execute: it is dead code.

I think we are better enforcing the elimination of the statement as this wrong analysis (or translation) of the number of iterations could produce wrong code.

> I assume P_21 is c.7_12

the number after P_ is the ssa variable number, so P_21 is c.7_21.

> we have 0 <= i1 <= 2147483637, whereever that comes from.

you can think about i1 as a canonical induction variable: 0 <= i1
and i1 is indexing all iterations in that loop: i.e., i1 is incremented by 1.

> Probably from the i1 <= 2147483637 constraint

this constraint is added based on the type of the induction variable that gives an upper bound for the iteration domain.

> 4294967296*floor((-1 - P_21)/4294967296) < -P_21 - i1

Yes, this constraint seems to be wrong.
Comment 20 rguenther@suse.de 2017-09-20 07:43:57 UTC
On Tue, 19 Sep 2017, spop at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69728
> 
> --- Comment #19 from Sebastian Pop <spop at gcc dot gnu.org> ---
> > So how'd we properly handle a valid empty domain?
> 
> DCE the statement.
> 
> If the domain for a statement is empty, it means that the statement does not
> execute: it is dead code.
> 
> I think we are better enforcing the elimination of the statement as this wrong
> analysis (or translation) of the number of iterations could produce wrong code.

That was my thinking, I put it on my TODO to figure out how to "DCE"
a stmt (or in this case it's rather the whole "loop body", right?).
I've not fully found my way through initial schedule building yet
(otherwise I would have tried refactoring to not operate in pbb
vector order but more naturally follow the SESE in a CFG walk with
maintaining a BB -> pbb mapping).

> > I assume P_21 is c.7_12
> 
> the number after P_ is the ssa variable number, so P_21 is c.7_21.
> 
> > we have 0 <= i1 <= 2147483637, whereever that comes from.
> 
> you can think about i1 as a canonical induction variable: 0 <= i1
> and i1 is indexing all iterations in that loop: i.e., i1 is incremented by 1.
> 
> > Probably from the i1 <= 2147483637 constraint
> 
> this constraint is added based on the type of the induction variable that gives
> an upper bound for the iteration domain.
> 
> > 4294967296*floor((-1 - P_21)/4294967296) < -P_21 - i1
> 
> Yes, this constraint seems to be wrong.

It indeed looks like so though I wasn't able to nail down what goes wrong.
Unfortunately the extract_affine fixes didn't affect this one in a 
positive way.
Comment 21 Richard Biener 2017-09-20 12:18:41 UTC
Oh, fixed on trunk only.
Comment 22 Sebastian Pop 2017-09-20 13:35:33 UTC
> I put it on my TODO to figure out how to "DCE" a stmt
> (or in this case it's rather the whole "loop body", right?).

The code generator would not even see a statement to be generated: it would just disappear in the new code, so there is nothing to do to DCE statements with empty domains.

> I've not fully found my way through initial schedule building yet
> (otherwise I would have tried refactoring to not operate in pbb
> vector order but more naturally follow the SESE in a CFG walk with
> maintaining a BB -> pbb mapping).

Yes, DOM-walk could be used to detect the sequential order in which basic blocks are executed.

There are some difficulties in giving an execution sequence number for if-then and if-else clauses, and for switch cases: for the moment we represent them as executing in sequence.  For example,

if (c)
  a;
else
  b;

we would number the stmts a and b as if the code looked like this:

if (c)
  a;
if (!c)
  b;

which is correct.
The fact that the constraint "c" is added to the iteration domain of "a", and "!c" added to the iter domain of "b" allows the scheduler to know that there are no sequential dependences between stmts "a" and "b" as they are executed in different iterations.
Comment 23 Richard Biener 2017-10-12 14:09:54 UTC
Author: rguenth
Date: Thu Oct 12 14:09:21 2017
New Revision: 253677

URL: https://gcc.gnu.org/viewcvs?rev=253677&root=gcc&view=rev
Log:
2017-10-12  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/69728
	Revert
	2017-09-19  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/69728
	* graphite-sese-to-poly.c (schedule_error): New global.
	(add_loop_schedule): Handle empty domain by failing the
	schedule.
	(build_original_schedule): Handle schedule_error.

	* graphite-sese-to-poly.c (add_loop_schedule): Handle empty
	domain by returning an unchanged schedule.

	* gcc.dg/graphite/pr69728.c: Adjust to reflect we can handle
	the loop now.  Remove unrelated undefined behavior.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/graphite-sese-to-poly.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gcc.dg/graphite/pr69728.c
Comment 24 Jakub Jelinek 2018-10-26 10:22:06 UTC
GCC 6 branch is being closed
Comment 25 Richard Biener 2019-11-14 09:13:58 UTC
Fixed in GCC 8.
Comment 26 Arseny Solokha 2019-11-14 15:12:20 UTC
This this PR be closed now?
Comment 27 Eric Gallager 2019-11-15 03:06:10 UTC
(In reply to Arseny Solokha from comment #26)
> This this PR be closed now?

Yeah I think that's what Richard meant to do