<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 - [GVN] Incorrect transformation if there is a !invariant.load"
   href="https://bugs.llvm.org/show_bug.cgi?id=42151">42151</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[GVN] Incorrect transformation if there is a !invariant.load
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

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

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

        <tr>
          <th>OS</th>
          <td>Windows NT
          </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>Scalar Optimizations
          </td>
        </tr>

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

        <tr>
          <th>Reporter</th>
          <td>serguei.katkov@azul.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>The following test shows the incorrect transformation done by GVN if there are
two loads of the same memory and one them is marked as invariant.

According to LangRef:
If a load instruction tagged with the !invariant.load metadata is executed, the
optimizer may assume the memory location referenced by the load contains the
same value at all points in the program where the memory location is known to
be dereferenceable; otherwise, the behavior is undefined.

The key words here is "If a load instruction tagged with the !invariant.load
metadata is executed".

In the example below, if incoming %cmp is always true then invariant load is a
dead runtime code and return value is always equal to 0 (this would be correct
transformation).

If I understand implementation correctly the problem is in caching the result.
When Query load is invariant the result is cached and next time when Query load
is not invariant the cached result is used.

However, invariant property affect the way stores are processed.

The reporducer:
========================================================
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:1"
target triple = "x86_64-unknown-linux-gnu"

declare void @llvm.memset.p0i8.i8(i8*, i8, i32, i1)
declare void @foo(i8*)

define i8 @test(i1 %cmp) {
entry:
  %p = alloca i8
  %addr = getelementptr inbounds i8, i8* %p, i64 1
  store i8 5, i8* %addr
  br label %header
header:
  %i = phi i8 [0, %entry], [%i.inc, %backedge]
  br i1 %cmp, label %alive, label %dead
dead:
  call void @foo(i8* %p)
  %v = load i8, i8* %addr, !invariant.load !1
  %i.1 = add i8 %i, %v
  br label %alive
alive:
  %i.2 = phi i8 [%i, %header], [%i.1, %dead]
  store i8 -5, i8* %addr
  br label %backedge
backedge:
  call void @llvm.memset.p0i8.i8(i8 * align 1 %p, i8 0, i32 2, i1 false)
  %i.inc = add i8 %i.2, 1
  %cmp.loop = icmp ugt i8 %i.inc, 100
  br i1 %cmp.loop, label %exit, label %header
exit:
  %res = load i8, i8* %addr
  ret i8 %res
}

!1 = !{}
========================================================
$ opt -S -passes=gvn ./repro.ll -debug-only=gvn
GVN iteration: 0
GVN REMOVING NONLOCAL LOAD:   %v = load i8, i8* %addr, !invariant.load !0
GVN removed:   %v = load i8, i8* %addr, !invariant.load !0
GVN removed:   %i.1 = add i8 %i, undef
GVN removed:   %i.2 = phi i8 [ %i, %header ], [ undef, %dead ]
GVN REMOVING NONLOCAL LOAD:   %res = load i8, i8* %addr
GVN removed:   %res = load i8, i8* %addr
GVN iteration: 1
; ModuleID = './repro.ll'
source_filename = "./repro.ll"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:1"
target triple = "x86_64-unknown-linux-gnu"

declare void @foo(i8*)

define i8 @test(i1 %cmp) {
entry:
  %p = alloca i8
  %addr = getelementptr inbounds i8, i8* %p, i64 1
  store i8 5, i8* %addr
  br label %header

header:                                           ; preds = %alive, %entry
  %i = phi i8 [ 0, %entry ], [ %i.inc, %alive ]
  br i1 %cmp, label %alive, label %dead

dead:                                             ; preds = %header
  call void @foo(i8* %p)
  br label %alive

alive:                                            ; preds = %dead, %header
  store i8 -5, i8* %addr
  call void @llvm.memset.p0i8.i32(i8* align 1 %p, i8 0, i32 2, i1 false)
  %i.inc = add i8 %i, 1
  %cmp.loop = icmp ugt i8 %i.inc, 100
  br i1 %cmp.loop, label %exit, label %header

exit:                                             ; preds = %alive
  ret i8 undef
}

; Function Attrs: argmemonly nounwind
declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg)
#0

attributes #0 = { argmemonly nounwind }
========================================================</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>