[llvm-bugs] [Bug 35092] New: Wrong answer after DeadStoreElimination on combination of Stores and memset

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Oct 26 01:42:36 PDT 2017


https://bugs.llvm.org/show_bug.cgi?id=35092

            Bug ID: 35092
           Summary: Wrong answer after DeadStoreElimination on combination
                    of Stores and memset
           Product: new-bugs
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: new bugs
          Assignee: unassignedbugs at nondot.org
          Reporter: ilia.taraban at intel.com
                CC: llvm-bugs at lists.llvm.org

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;
}

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

>>> clang -v
clang version 6.0.0 (trunk 316636)
Target: x86_64-unknown-linux-gnu
Thread model: posix
...

>>> clang -O0 -o nice.exe nice.c
>>> ./nice.exe
7

>>> clang -O2 -o nice.exe nice.c
>>> ./nice.exe
0

>>> clang -O2 -o nice.exe nice.c -mllvm -opt-bisect-limit=53 && ./nice.exe
...
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

>>> clang -O2 -o nice.exe nice.c -mllvm -opt-bisect-limit=54 && ./nice.exe
...
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:
>>> clang -O2 -o nice-before.ll nice.c -mllvm -opt-bisect-limit=53 -S -emit-llvm

================= 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:
>>> opt nice-before.ll -o nice.after.ll -S -dse

================= 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;

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20171026/e24aeca1/attachment-0001.html>


More information about the llvm-bugs mailing list