Bug 58736 - IVOPTs rewrites unsigned to signed arith, exposing undefined overflow
Summary: IVOPTs rewrites unsigned to signed arith, exposing undefined overflow
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: ---
Assignee: Richard Biener
URL:
Keywords: wrong-code
Depends on:
Blocks: 58143
  Show dependency treegraph
 
Reported: 2013-10-15 11:06 UTC by Richard Biener
Modified: 2013-10-15 11:54 UTC (History)
0 users

See Also:
Host:
Target: x86_64-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-10-15 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2013-10-15 11:06:25 UTC
Split out from PR58143,

/* { dg-do run } */
/* { dg-additional-options "-fstrict-overflow" } */

int a, b, c, d, e;

int
main ()
{
  for (b = 4; b > -30; b--)
    {
      e = a > (int)((unsigned int) __INT_MAX__ - (unsigned int) b);
      for (; c;)
        for (;;)
          {
            if (d)
              break;
          }
    }
  return 0;
}

is compiled to an infinite loop at -O3 by IVOPTs and VRP teaming up,
rewriting (unsigned int) __INT_MAX__ - (unsigned int) b as signed arithmetic
and then removing the loop exit test.
Comment 1 Richard Biener 2013-10-15 11:08:40 UTC
I will have a look.
Comment 2 Richard Biener 2013-10-15 11:37:42 UTC
rewrite_use_compare rewrites

  b.1_5 = (unsigned int) b.0_20;
  _6 = 2147483647 - b.1_5;
  _7 = (int) _6;
  _9 = _7 < pretmp_23;

into

  _13 = 2147483647 - b.0_20;
  _9 = _13 < pretmp_23;

here:

  /* The induction variable elimination failed; just express the original
     giv.  */
  comp = get_computation (data->current_loop, use, cand);

using the candidate b.0_20 where already the affine form of the
computation is wrong:

{
  type = int
  offset = 2147483647
  elements = {
    [0] = b.0_20 * -1
  }
}

which is because the use induction variable for _7 is wrongly determined by
simple_iv as { 2147483643, +, 1 } (but it has ->no_overflow == false but
nothing in IVOPTs ever checks that which looks like a bug).
Comment 3 Richard Biener 2013-10-15 11:41:18 UTC
The following patch fixes this and the testcase.

Index: gcc/tree-ssa-loop-ivopts.c
===================================================================
--- gcc/tree-ssa-loop-ivopts.c  (revision 203590)
+++ gcc/tree-ssa-loop-ivopts.c  (working copy)
@@ -1084,6 +1084,13 @@ find_givs_in_stmt_scev (struct ivopts_da
 
   if (!simple_iv (loop, loop_containing_stmt (stmt), lhs, iv, true))
     return false;
+
+  /* If the induction variable invokes undefined behavior when it wraps
+     make sure it does not overflow.  */
+  if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (lhs))
+      && !iv->no_overflow)
+    return false;
+
   iv->base = expand_simple_operations (iv->base);
 
   if (contains_abnormal_ssa_name_p (iv->base)
Comment 4 Richard Biener 2013-10-15 11:54:35 UTC
Err.  Triggered by local changes in my tree.