This is a regression present on mainline, 9 and 8 branches, but the underlying 
issue is probably latent on the 7 branch.  compare_values in tree-vrp.c can 
rely on undefined overflow to compare symbolic expressions with constants so 
we must make sure not to introduce such an overflow when combining ranges with 
symbolic expressions.

Tested on x86_64-suse-linux, OK for all active branches?


2019-10-23  Eric Botcazou  <ebotca...@adacore.com>

        PR tree-optimization/92131
        * tree-vrp.c (extract_range_from_plus_minus_expr): If the resulting
        range would be symbolic, drop to varying for any explicit overflow
        in the constant part or if one of the ranges is not a singleton.


2019-10-23  Eric Botcazou  <ebotca...@adacore.com>

        * gcc.c-torture/execute/20191023-1.c: New test.

-- 
Eric Botcazou
Index: tree-vrp.c
===================================================================
--- tree-vrp.c	(revision 277149)
+++ tree-vrp.c	(working copy)
@@ -1652,7 +1652,7 @@ extract_range_from_plus_minus_expr (valu
   value_range_kind vr0_kind = vr0.kind (), vr1_kind = vr1.kind ();
   tree vr0_min = vr0.min (), vr0_max = vr0.max ();
   tree vr1_min = vr1.min (), vr1_max = vr1.max ();
-  tree min = NULL, max = NULL;
+  tree min = NULL_TREE, max = NULL_TREE;
 
   /* This will normalize things such that calculating
      [0,0] - VR_VARYING is not dropped to varying, but is
@@ -1715,18 +1715,19 @@ extract_range_from_plus_minus_expr (valu
       combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1);
       combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1);
 
-      /* If we have overflow for the constant part and the resulting
-	 range will be symbolic, drop to VR_VARYING.  */
-      if (((bool)min_ovf && sym_min_op0 != sym_min_op1)
-	  || ((bool)max_ovf && sym_max_op0 != sym_max_op1))
+      /* If the resulting range will be symbolic, we need to eliminate any
+	 explicit or implicit overflow introduced in the above computation
+	 because compare_values could make an incorrect use of it.  That's
+	 why we require one of the ranges to be a singleton.  */
+      if ((sym_min_op0 != sym_min_op1 || sym_max_op0 != sym_max_op1)
+	  && ((bool)min_ovf || (bool)max_ovf
+	      || (min_op0 != max_op0 && min_op1 != max_op1)))
 	{
 	  vr->set_varying (expr_type);
 	  return;
 	}
 
       /* Adjust the range for possible overflow.  */
-      min = NULL_TREE;
-      max = NULL_TREE;
       set_value_range_with_overflow (kind, min, max, expr_type,
 				     wmin, wmax, min_ovf, max_ovf);
       if (kind == VR_VARYING)
/* PR tree-optimization/92131 */
/* Testcase by Armin Rigo <ar...@tunes.org> */

long b, c, d, e, f, i;
char g, h, j, k;
int *aa;

static void error (void) __attribute__((noipa));
static void error (void) { __builtin_abort(); }

static void see_me_here (void) __attribute__((noipa));
static void see_me_here (void) {}

static void aaa (void) __attribute__((noipa));
static void aaa (void) {}

static void a (void) __attribute__((noipa));
static void a (void) {
  long am, ao;
  if (aa == 0) {
    aaa();
    if (j)
      goto ay;
  }
  return;
ay:
  aaa();
  if (k) {
    aaa();
    goto az;
  }
  return;
az:
  if (i)
    if (g)
      if (h)
        if (e)
          goto bd;
  return;
bd:
  am = 0;
  while (am < e) {
    switch (c) {
    case 8:
      goto bh;
    case 4:
      return;
    }
  bh:
    if (am >= 0)
      b = -am;
    ao = am + b;
    f = ao & 7;
    if (f == 0)
      see_me_here();
    if (ao >= 0)
      am++;
    else
      error();
  }
}

int main (void)
{
    j++;
    k++;
    i++;
    g++;
    h++;
    e = 1;
    a();
    return 0;
}

Reply via email to