<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Wrong answer after DeadStoreElimination on combination of Stores and memset"
   href="https://bugs.llvm.org/show_bug.cgi?id=35092">35092</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Wrong answer after DeadStoreElimination on combination of Stores and memset
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>new bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>ilia.taraban@intel.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>This test fails at runfail with wrong answer after DeadStoreElimination on
combinations of Stores and memset intrin:

================= nice.c ==============
char i = 0;
char s [5] = {0};
int main ()
{
    for (i = 1; i <= 2; i++) 
    {
        char m = 0;
        for (m = i; m <= 4; m++) 
            s[m] = 0;
        s[i + 1] = 7;
    }
    printf(0);
    printf("%d", s[3]);
    return 0;
}

=======================================

<span class="quote">>>> clang -v</span >
clang version 6.0.0 (trunk 316636)
Target: x86_64-unknown-linux-gnu
Thread model: posix
...

<span class="quote">>>> clang -O0 -o nice.exe nice.c
>>> ./nice.exe</span >
7

<span class="quote">>>> clang -O2 -o nice.exe nice.c
>>> ./nice.exe</span >
0

<span class="quote">>>> clang -O2 -o nice.exe nice.c -mllvm -opt-bisect-limit=53 && ./nice.exe</span >
...
BISECT: running pass (52) Jump Threading on function (main)
BISECT: running pass (53) Value Propagation on function (main)
BISECT: NOT running pass (54) Dead Store Elimination on function (main)
BISECT: NOT running pass (55) Aggressive Dead Code Elimination on function
(main)
...
7

<span class="quote">>>> clang -O2 -o nice.exe nice.c -mllvm -opt-bisect-limit=54 && ./nice.exe</span >
...
BISECT: running pass (53) Value Propagation on function (main)
BISECT: running pass (54) Dead Store Elimination on function (main)
BISECT: NOT running pass (55) Aggressive Dead Code Elimination on function
(main)
BISECT: NOT running pass (56) Simplify the CFG on function (main)
...
0

Now let's look at IR before and after Dead Store Elimination:
<span class="quote">>>> clang -O2 -o nice-before.ll nice.c -mllvm -opt-bisect-limit=53 -S -emit-llvm</span >

================= nice-before.ll ==============
; Function Attrs: nounwind uwtable
define i32 @main() local_unnamed_addr #0 {
for.end.1:
  store i8 1, i8* @i, align 1, !tbaa !2
  store i32 0, i32* bitcast (i8* getelementptr inbounds ([5 x i8], [5 x i8]*
@s, i64 0, i64 1) to i32*), align 1
  store i8 7, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @s, i64 0, i64
2), align 1, !tbaa !2
  call void @llvm.memset.p0i8.i64(i8* getelementptr inbounds ([5 x i8], [5 x
i8]* @s, i64 0, i64 2), i8 0, i64 3, i32 1, i1 false)
  store i8 7, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @s, i64 0, i64
3), align 1, !tbaa !2
  store i8 3, i8* @i, align 1, !tbaa !2
  %call = tail call i32 (i8*, ...) @printf(i8* null)
  %0 = load i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @s, i64 0, i64
3), align 1, !tbaa !2
  %conv13 = sext i8 %0 to i32
  %call14 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x
i8], [3 x i8]* @.str, i64 0, i64 0), i32 %conv13)
  ret i32 0
}

==============================================

and after:
<span class="quote">>>> opt nice-before.ll -o nice.after.ll -S -dse</span >

================= nice-after.ll ==============
; Function Attrs: nounwind uwtable
define i32 @main() local_unnamed_addr #0 {
for.end.1:
  store i32 460544, i32* bitcast (i8* getelementptr inbounds ([5 x i8], [5 x
i8]* @s, i64 0, i64 1) to i32*), align 1
  call void @llvm.memset.p0i8.i64(i8* getelementptr inbounds ([5 x i8], [5 x
i8]* @s, i64 0, i64 2), i8 0, i64 3, i32 1, i1 false)
  store i8 3, i8* @i, align 1, !tbaa !2
  %call = tail call i32 (i8*, ...) @printf(i8* null)
  %0 = load i8, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @s, i64 0, i64
3), align 1, !tbaa !2
  %conv13 = sext i8 %0 to i32
  %call14 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x
i8], [3 x i8]* @.str, i64 0, i64 0), i32 %conv13)
  ret i32 0
}
==============================================

If we look at debug, we'll see that DeadStore merge second and third stores:
    DSE: Partial overwrite: Earlier [1, 5) Later [2, 3)
    DSE: Partial overwrite an earlier load [1, 5) by a later store [2, 3)
    DSE: Merge Stores:
        Earlier:   store i32 0, i32* bitcast (i8* getelementptr inbounds ([5 x
i8], [5 x i8]* @s, i64 0, i64 1) to i32*), align 1
    Later:   store i8 7, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @s,
i64 0, i64 2), align 1, !tbaa !2
        Merged Value: 1792
Then it tries to merge memset with store, but fails in dynamic_cast memset
intrin to store inst class, and then it merge it with next store, which is
incorrect:
    DSE: Partial overwrite: Earlier [2, 5) Later [3, 4)
    DSE: Partial overwrite an earlier load [2, 5) by a later store [3, 4)
    DSE: Partial overwrite: Earlier [1, 5) Later [3, 4)
    DSE: Partial overwrite an earlier load [1, 5) by a later store [3, 4)
    DSE: Merge Stores:
        Earlier:   store i32 1792, i32* bitcast (i8* getelementptr inbounds ([5
x i8], [5 x i8]* @s, i64 0, i64 1) to i32*), align 1
        Later:   store i8 7, i8* getelementptr inbounds ([5 x i8], [5 x i8]*
@s, i64 0, i64 3), align 1, !tbaa !2
        Merged Value: 460544

I think maybe problem is in check after merging part, because after failing in
dynamic cast it just go on next iteteration throw block.
For example, AA at the end of the iteration returns MRI_Mod, but we check only
MRI_Ref, maybe we should change this if condition to more strict:
      // Can't look past this instruction if it might read 'Loc'.
      if (AA->getModRefInfo(DepWrite, Loc) & MRI_Ref)
        break;</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>