<div dir="ltr">Hi all,<div>I have a question about dereferenceable metadata on load instruction. I have a patch (<a href="https://reviews.llvm.org/D31539">https://reviews.llvm.org/D31539</a>) for LICM that hoists loads with !invariant.group.</div><div>The motivation example is devirtualization:</div><div> </div><div><div>struct A {</div><div>   virtual void foo();</div><div>};</div><div>int bar();</div><div>void indirect(A &a) {</div><div>  while(bar())</div><div>       a.foo();</div><div>}</div></div><div><br></div><div>With -O2 -fstrict-vtable-pointers we get:</div><div><br></div><div><div>define void @hoist(%struct.A* dereferenceable(8)) {</div><div>entry:</div><div>  %call1 = tail call i32 @bar()</div><div>  %tobool2 = icmp eq i32 %call1, 0</div><div>  br i1 %tobool2, label %while.end, label %<a href="http://while.body.lr.ph">while.body.lr.ph</a></div><div><br></div><div><a href="http://while.body.lr.ph">while.body.lr.ph</a>:                                 ; preds = %entry</div><div>  %b = bitcast %struct.A* %0 to void (%struct.A*)***</div><div><br></div><div>  br label %while.body</div><div><br></div><div>while.body:                                       ; preds = %<a href="http://while.body.lr.ph">while.body.lr.ph</a>, %while.body</div><div>  %vtable = load void (%struct.A*)**, void (%struct.A*)*** %b, align 8, !invariant.group !0</div><div>  %1 = load void (%struct.A*)*, void (%struct.A*)** %vtable, align 8, !invariant.load !0</div><div>  tail call void %1(%struct.A* %0)</div><div>  %call = tail call i32 @bar()</div><div>  %tobool = icmp eq i32 %call, 0</div><div>  br i1 %tobool, label %while.end.loopexit, label %while.body</div><div><br></div><div>while.end.loopexit:                               ; preds = %while.body</div><div>  br label %while.end</div><div><br></div><div>while.end:                                        ; preds = %while.end.loopexit, %entry</div><div>  ret void</div><div>}</div></div><div><br></div><div><br></div><div><br></div><div>We know that the load of vptr and virtual function will not change in this loop, which is indicated by !invariant.group.</div><div>Hoisting invariant.group load is legal because %b is dereferenceable, but hoisting next load is illegal by LICM because it can't prove that %vtable is dereferenceable.</div><div>But if I add dereferenceable metadata on vtable load like</div><div><br></div><div>%vtable = load void (%struct.A*)**, void (%struct.A*)*** %b, align 8, !invariant.group !0, !dereferenceable !1<br></div><div>!1 = !{i64 8}</div><div><br></div><div>Then it doesn't help either, because LICM drops !dereferencealbe metadata when hoisting (and adding it would be invalid, because we don't know if it is also dereferenceable in hoisted block).</div><div><br></div><div>On the other hand, after performing my LICM of !invariant.group load, GVN hoists the second load and I am not sure why it is legal then.</div><div><br></div><div>Any ideas?</div><div><br></div><div>Piotr</div></div>