[LLVMdev] opt -O2 leads to incorrect operation (possibly a bug in the DSE)

Hal Finkel
Fri, 17 Oct 2014 11:30:41 -0000

----- Original Message -----
> From: "Aliaksei Zasenka" <listhex at gmail.com>
> To: LLVMdev at cs.uiuc.edu
> Sent: Friday, October 17, 2014 4:24:27 AM
> Subject: [LLVMdev] opt -O2 leads to incorrect operation (possibly a bug in
the DSE)
>
> Hi all,
>
> Consider the following example:
>
> define void @fn(i8* %buf) #0 {
> entry:
> %arrayidx = getelementptr i8* %buf, i64 18
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arrayidx, i8* %buf,
> i64 18, i32 1, i1 false)
> %arrayidx1 = getelementptr i8* %buf, i64 18
> store i8 1, i8* %arrayidx1, align 1
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %buf, i8* %arrayidx,
> i64 18, i32 1, i1 false)
> ret void
> }
>
>
>
> I ran opt -O2 ex.ll -S, and got:
>
> define void @fn(i8* nocapture %buf) #0 {
> entry:
> %arrayidx = getelementptr i8* %buf, i64 18
> store i8 1, i8* %arrayidx, align 1
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %buf, i8* %arrayidx,
> i64 18, i32 1, i1 false)
> ret void
> }
>
>
> In that case previous contents of bytes 0-17 are overwritten by bytes
> 18-35 (pre-opt code doesn't do that).
>
>
>
> Another point, if I change the code to:
>
> define void @fn(i8* %buf) #0 {
> entry:
> %arrayidx = getelementptr i8* %buf, i64 18
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arrayidx, i8* %buf,
> i64 18, i32 1, i1 false)
>
> ;changing 19th byte, not 18th:
>
> %arrayidx1 = getelementptr i8* %buf, i64 19
> store i8 1, i8* %arrayidx1, align 1
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %buf, i8* %arrayidx,
> i64 18, i32 1, i1 false)
> ret void
> }
>
>
>
> I get correct piece of code:
>
> define void @fn(i8* nocapture %buf) #0 {
> entry:
> %arrayidx = getelementptr i8* %buf, i64 18
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arrayidx, i8* %buf,
> i64 18, i32 1, i1 false)
> %arrayidx1 = getelementptr i8* %buf, i64 19
> store i8 1, i8* %arrayidx1, align 1
> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %buf, i8* %arrayidx,
> i64 18, i32 1, i1 false)
> ret void
> }
>
> Adding some datalayout to module also solves the issue.
>
> -print-after-all shows that the 'Dead Store Elimination' pass
erases
> first call to memcpy.
>
> I found that the following code in DeadStoreElimination.cpp leads to
> such behavior:
> if (DL == nullptr && Later.Ptr->getType() ==
Earlier.Ptr->getType())
> return OverwriteComplete;
>
>
> Is this issue a bug in DSE or maybe I'm doing some wrong?
>

Looks like a bug in DSE, you're not doing anything wrong. We don't test
much without data layouts anymore. This code might pre-date DSE's handling
of memcpy intrinsics (just a guess). In any case, we'll fix it.

 -Hal

>
>
>
> Best regards,
> Alexey
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>

--
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory