Hi all,
I have a question about dereferenceable metadata on load instruction. I have a patch (https://reviews.llvm.org/D31539) for LICM that hoists loads with !invariant.group.
The motivation example is devirtualization:
struct A {
virtual void foo();
};
int bar();
void indirect(A &a) {
while(bar())
a.foo();
}
With -O2 -fstrict-vtable-pointers we get:
define void @hoist(%struct.A* dereferenceable(8)) {
entry:
%call1 = tail call i32 @bar()
%tobool2 = icmp eq i32 %call1, 0
br i1 %tobool2, label %while.end, label %while.body.lr.ph
while.body.lr.ph: ; preds = %entry
%b = bitcast %struct.A* %0 to void (%struct.A*)***
br label %while.body
while.body: ; preds = %while.body.lr.ph, %while.body
%vtable = load void (%struct.A*), void (%struct.A*)* %b, align 8, !invariant.group !0
%1 = load void (%struct.A*), void (%struct.A)** %vtable, align 8, !invariant.load !0
tail call void %1(%struct.A* %0)
%call = tail call i32 @bar()
%tobool = icmp eq i32 %call, 0
br i1 %tobool, label %while.end.loopexit, label %while.body
while.end.loopexit: ; preds = %while.body
br label %while.end
while.end: ; preds = %while.end.loopexit, %entry
ret void
}
We know that the load of vptr and virtual function will not change in this loop, which is indicated by !invariant.group.
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.
But if I add dereferenceable metadata on vtable load like
%vtable = load void (%struct.A*), void (%struct.A*)* %b, align 8, !invariant.group !0, !dereferenceable !1
!1 = !{i64 8}
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).
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.
Any ideas?
Piotr