https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89497

--- Comment #15 from Martin Liška <marxin at gcc dot gnu.org> ---
There's a more readable test-case:

$ echo =1= && cat 1.i && echo =2= && cat 2.i && echo =3= && cat 3.i && echo =4=
&& cat 4.i
=1=
int guard;
int cupsArraySave() {
  if (guard)
    return 0;
  else
    return 1;
}
=2=
int *get_null() { return 0; }
=3=
unsigned long _cups_strlcpy(char *, char *, long);

typedef struct {
  char array[81];
} container;

container *get();
container *get_null();

container c;

void d() {
  container *a = get();
  for (; a; a = get_null()) {
    cupsArraySave();
    _cups_strlcpy(a->array, c.array, sizeof(c.array));
  }
}
=4=
unsigned long _cups_strlcpy(char *dest, char *src, long len) {
  unsigned long len2 = __builtin_strlen(src);
  if (len2 > len)
    len2 = len;
  __builtin_memmove(dest, src, len2);
}

We ICE in tree-vrp where:

SSA form after inserting ASSERT_EXPRs
d ()
{
  int D.4365;
  long unsigned int len2;
  int * D.4357;
  struct container * a;
  char[81] * _1;
  int _18;
  int _19;

  <bb 2> [local count: 118111600]:
  a_6 = get ();
  goto <bb 9>; [100.00%]

  <bb 3> [local count: 955630223]:
  a_10 = ASSERT_EXPR <a_2, a_2 != 0B>;
  _18 = guard;
  if (_18 != 0)
    goto <bb 5>; [50.00%]
  else
    goto <bb 4>; [50.00%]

  <bb 4> [local count: 477815111]:

  <bb 5> [local count: 955630223]:
  # _19 = PHI <0(3), 1(4)>
  _1 = &a_10->array;
  len2_15 = __builtin_strlen (&c.array);
  if (len2_15 > 81)
    goto <bb 6>; [50.00%]
  else
    goto <bb 11>; [50.00%]

  <bb 11> [local count: 477815112]:
  len2_23 = ASSERT_EXPR <len2_15, len2_15 <= 81>;
  goto <bb 7>; [100.00%]

  <bb 6> [local count: 477815111]:
  len2_14 = ASSERT_EXPR <len2_15, len2_15 > 81>;

  <bb 7> [local count: 955630223]:
  # len2_17 = PHI <81(6), len2_23(11)>
  __builtin_memmove (_1, &c.array, len2_17);

  <bb 8> [local count: 955630223]:
  # a_20 = PHI <0B(7)>
  goto <bb 10>; [100.00%]

  <bb 9> [local count: 118111601]:
  # a_2 = PHI <a_6(2)>
  if (a_2 != 0B)
    goto <bb 3>; [97.00%]
  else
    goto <bb 10>; [3.00%]

  <bb 10> [local count: 118111601]:
  return;

}

...
Visiting statement:
_1 = &a_2->array;
LKUP STMT len2_15 = __builtin_strlen (&c.array) with .MEM_11
<<<< COPY _19 = 0
  Registering jump thread: (3, 5) incoming edge;  (5, 11) normal;
<<<< STMT 0 = a_2 eq_expr 0B
<<<< STMT 1 = a_2 ne_expr 0B
<<<< COPY a_10 = a_2
  Threaded jump 4 --> 5 to 12
  Threaded jump 3 --> 5 to 12
Removing basic block 5
;; basic block 5, loop depth 0
;;  pred:      
# _19 = PHI <>
_1 = &a_2->array;
len2_15 = __builtin_strlen (&c.array);
if (0 != 0)
  goto <bb 6>; [100.00%]
else
  goto <bb 11>; [0.00%]
;;  succ:       6
;;              11
...

after the BB removal we end up with:

(gdb) p debug_function(cfun->decl, 0)
d ()
{
  int D.4365;
  long unsigned int len2;
  int * D.4357;
  struct container * a;
  char[81] * _1;
  int _18;
  int _19;
  int _24;
  char[81] * _25;

  <bb 2> [local count: 118111601]:
  a_6 = get ();
  if (a_6 != 0B)
    goto <bb 3>; [97.00%]
  else
    goto <bb 10>; [3.00%]

  <bb 3> [local count: 955630223]:
  _18 = guard;
  if (_18 != 0)
    goto <bb 12>; [50.00%]
  else
    goto <bb 4>; [50.00%]

  <bb 4> [local count: 477815111]:
  goto <bb 12>; [100.00%]

  <bb 11> [local count: 477815112]:

  <bb 7> [local count: 955630223]:
  # len2_17 = PHI <len2_15(12)>
  __builtin_memmove (_1, &c.array, len2_17);

  <bb 8> [local count: 955630223]:

  <bb 10> [local count: 118111601]:
  return;

  <bb 12> [local count: 477815112]:
  # _24 = PHI <1(4), 0(3)>
  _25 = &a_6->array;
  len2_26 = __builtin_strlen (&c.array);
  goto <bb 7>; [100.00%]

}

Note that _1 has missing definition.
And we segfault in cleanup_tree_cfg_bb where we're trying to fold
__builtin_memmove (_1, &c.array, len2_17);

Am I correct that the bb removal should propagate _1 into the
__builtin_memmove?
Maybe a broken DEF-USE chain?

Reply via email to