[llvm-dev] Dereferenceable load semantics & LICM
Piotr Padlewski via llvm-dev
llvm-dev at lists.llvm.org
Thu Apr 6 02:36:31 PDT 2017
2017-04-05 18:30 GMT+02:00 Sanjoy Das <sanjoy at playingwithpointers.com>:
> Hi Piotr,
>
> On Mon, Apr 3, 2017 at 2:01 PM, Piotr Padlewski
> <piotr.padlewski at gmail.com> wrote:
> >> I don't see any way to model it right now in LLVM, but I see a one
> simple
> >> solution:
> >> add extra information to the metadata nodes indicating that this
> property
> >> is non-local:
> >>
> >> %0 = load... %p, !invariant.group !1, !dereferenceable !2
> >> %1 = load ... %0, !invariant.load !0, !dereferenceable !2
> >>
> >> !0 = !{!"GlobalProperty"}
> >> !1 = !{!"MyType", !"GlobalProperty"}
> >> !2 = !{i64 8, !"GlobalProperty}
> >>
> >> With that we would strip only the metadata not containing this
> >> information.
> >>
> >> For devirtualization it would make sense with invariant.load,
> >> invariant.group and dereferenceable.
> >>
> >> What do you think about this idea?
>
> I'm sorry for being *this* annoying, but I'm not on board with this. :)
>
> I think this will run into the same dead-code-can-affect-behavior
> issue discussed in https://reviews.llvm.org/D20116.
>
> Specifically, if your program is:
>
> if (false) {
> ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8, !"GlobalProperty}
> // ptr is not actually dereferenceable, even the load above has UB
> // (since the metadata is "wrong"), but it is never executed so all is
> well.
> int val = *ptr;
> }
>
> then you could transform it to
>
> ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8, !"GlobalProperty}
> // ptr is not actually dereferenceable
> int val = *ptr;
> if (false) {
> }
>
> and you'd have gone from a program with no UB to one with UB.
>
> -- Sanjoy
>
I disagree, I find it different than the patch you mentioned. We don't have
any problems with code like this:
ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8}
if (false) {
// ptr is not actually dereferenceable, even the load above has UB
// (since the metadata is "wrong"), but it is never executed so all is
well.
int val = *ptr;
}
because we rely on the information provided by someone else that ptr is
dereferenceable, so we can transform it to
ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8}
// ptr is not actually dereferenceable
int val = *ptr;
if (false) {
}
And this is exactly how we treat any other UB.
It is also important to mention that in order to perform optimization you
have mentioned we need to know that %ptrptr is also dereferenceable.
The vptr and vtable properties are non local, so I don't see how
hoisting vptr load could be dangerous:
void foo(A& a) {
if (false)
a.foo();
}
will be:
void foo(A* dereferenceable(8) %a) {
if (false)
%vptr = load %a, !dereferenceable !{VtableSize, "GlobalProperty"},
!invariant.group !0
%vfunction = load %vptr, !invariant.load !0
call %vfunction();
}
and after hoisting:
void foo(A* dereferenceable(8) %a) {
%vptr = load %a, !dereferenceable !{VtableSize, "GlobalProperty"},
!invariant.group !{"GlobalProperty"}
%vfunction = load %vptr, !invariant.load !{"GlobalProperty"}
if (false)
call %vfunction();
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170406/ed368791/attachment.html>
More information about the llvm-dev
mailing list