[llvm-dev] A bug related with undef value when bootstrap MemorySSA.cpp

Wei Mi via llvm-dev llvm-dev at lists.llvm.org
Sat Jul 15 17:11:20 PDT 2017


This is a bug found by internal compiler bootstrap, and possibly it is
the root cause of https://bugs.llvm.org/show_bug.cgi?id=33652 and
https://bugs.llvm.org/show_bug.cgi?id=33626.

Here is the testcase 1.c. The original code is at MemorySSA.cpp:586
for rL307764.

------------------------- 1.c ---------------------------
long a, c, d, e, f, m, cnt, i_hasval;
volatile long b;
void goo(long);
void hoo();
long ioo();

void foo(long hasval) {
  long i, k;
  if (hasval) {
    i = b;
  }

  k = 0;
  do {
    if (i_hasval != hasval)
      return;
    if (i_hasval) {
      m = m + 1;
      if (a == i) {
        c = a + d + e + f;
        return;
      }
    }
    c = a + b;
    i_hasval = 3;
    k++;
  } while (k < cnt);
}

void hoo() {
  foo(0);
}
------------------------------------------------------

I verified the problem existed from
llvm-r295736 to the head of trunk using 1.c (I didn't try older version)

~/workarea/llvm-r295736/dbuild/bin/clang -O3 -S 1.c -mllvm
-jump-threading-threshold=0 -fno-vectorize

Here is hoo's assembly code, note that there is no store to c(%rip)
inside of it, and it is wrong.

hoo:                                    # @hoo
        .cfi_startproc
# BB#0:                                 # %entry
        movq    cnt(%rip), %rax
        cmpq    $0, i_hasval(%rip)
        sete    %dl
        xorl    %ecx, %ecx
        .p2align        4, 0x90
.LBB1_1:                                # %do.body.us.i
                                        # =>This Inner Loop Header: Depth=1
        testb   $1, %dl
        je      .LBB1_3
# BB#2:                                 # %if.end2.us.i
                                        #   in Loop: Header=BB1_1 Depth=1
        movq    b(%rip), %rdx
        movq    $3, i_hasval(%rip)
        incq    %rcx
        xorl    %edx, %edx
        cmpq    %rax, %rcx
        jl      .LBB1_1
.LBB1_3:                                # %foo.exit
        retq

Here are the related llvm transformations (Note: look at the value of
i, i is undef when hasval is 0.):

1. The condition expr of if (a == i) is a loop invariant and is
promoted outside of do-while loop.

t = (a == i);         // loop invariant code motion
do {
    if (i_hasval != hasval)
      return;
    if (i_hasval) {
      m = m + 1;
      if (t) {
        c = a + d + e + f;
        return;
      }
    }
    c = a + b;
    i_hasval = 3;
    k++;
  } while (k < cnt);

2. Then the do-while loop is unswitched by if (a == i):

if (a == i) {
  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (true) {
          c = a + d + e + f;
          return;
        }
      }
      c = a + b;
      i_hasval = 3;
      k++;
   } while (k < cnt);
} else {
  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (false) {
          c = a + d + e + f;
          return;
        }
      }
      c = a + b;
      i_hasval = 3;
      k++;
    } while (k < cnt);
}

3. GVN does equality propagation to replace a with i inside of the first loop.

if (a == i) {
  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (true) {
          c = i + d + e + f;      // a is replaced with i.
          return;
        }
      }
      c = i + b;                     // a is replaced with i.
      i_hasval = 3;
      k++;
   } while (k < cnt);
} else {
  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (false) {
          c = a + d + e + f;
          return;
        }
      }
      c = a + b;
      i_hasval = 3;
      k++;
    } while (k < cnt);
}

4. after the callsite foo(0) is inlined into hoo, i becomes undef and
inliner propagates the undef of i to all the uses of i.

if (a == undef) {             // i is replaced with undef
  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (true) {
          c = undef + d + e + f;      // i is replaced with undef.
          return;
        }
      }
      c = undef + b;                     // i is replaced with undef.
      i_hasval = 3;
      k++;
   } while (k < cnt);
} else {
  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (false) {
          c = a + d + e + f;
          return;
        }
      }
      c = a + b;
      i_hasval = 3;
      k++;
    } while (k < cnt);
}

5. a == undef is simplified into true and the else branch is removed.

  do {
      if (i_hasval != hasval)
        return;
      if (i_hasval) {
        m = m + 1;
        if (true) {
          c = undef + d + e + f;      // store to c
          return;
        }
      }
      c = undef + b;                     // store to c
      i_hasval = 3;
      k++;
   } while (k < cnt);

We can see that c is always an undef value now after all these
transformations. That is why we cannot see store to c in the final
assembly. In the original program, c has a valid value at the end of
hoo.

Every transformation above seems of no problem, but the composition
result is wrong. It is still not clear which transformation to blame.

Thanks,
Wei.


More information about the llvm-dev mailing list