[llvm-dev] Dereferenceable load semantics & LICM

Piotr Padlewski via llvm-dev llvm-dev at lists.llvm.org
Fri Apr 7 08:01:38 PDT 2017


2017-04-06 23:47 GMT+02:00 Sanjoy Das <sanjoy at playingwithpointers.com>:

> Hi Piotr,
>
> On April 6, 2017 at 9:28:58 AM, Piotr Padlewski
> (piotr.padlewski at gmail.com) wrote:
> > Hi Sanjoy,
> > My point is that this it is exactly the same way as normal
> !dereferenceable
> > introduces UB.
> >
> > ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8}
> > if (false) {
> > int val = *ptr;
> > }
>
> These are two different things.
>
> In the above example, your original program executes a load that was
> supposed to produce a dereferenceable value, but it did not.  This
> means the original program is undefined, so we can optimize it to do
> whatever we want.
>
> OTOH, look at this program:
>
> void main() {
>   if (false) {
>     // ptrptr does not contain a dereferenceable pointer, but is
> itself dereferenceable
>     ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8}, !global
>     int val = *ptr;
>   }
> }
>
> What is the behavior of the above program?  It better be well defined,
> since it does nothing!
>
> However, if we follow your rules, we can first xform it to
>
> void main() {
>   ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8}, !global
>   if (false) {
>     int val = *ptr;
>   }
> }
>
> and then to
>
> void main() {
>   ptr = load i8*, i8** %ptrptr, !dereferenceable !{i64 8}, !global
>   int val = *ptr;
>   if (false) {
>   }
> }
>
> which introduces UB into a program that was well defined to begin
> with.
>
> > If frontend says that something is dereferenceable, which is not actually
> > dereferenceable, then it is UB and everything can happen - like the
> > execution of dead instruction.
> > This is exactly the same with the global properties - we are giving a
> > guarantee that pointer it is dereferenceable even if we would hoist or
> sink
> > it, and if it is not true then it is UB.
>
> But then you're saying dead code (code that would not actually execute
> in the original program) can affect program behavior, and: "if (false)
> X;" is not a no-op for some values of X.  It is in this respect that
> your proposal is similar to the speculatable proposal.
>
> Hi Sanjoy,
But we already have that behavior with dereferenceable variables.

void foo(i8* dereferenceable(8) %ptr) {
  if (false) {
    ; what if %x is not actually dereferenceable?
    %x = load i8, i8* %ptr
  }
}
Now we can hoist the load, even that it would be never executed.
This is the same with global properties - it gives us guarantee that
property holds non locally and if it doesn't then it is UB
and things like this might happen.

I understand your concerns about the speculate function attribute, the
examples that you showed in the review are pretty disturbing,
but loads and stores seems to be much safere in that maner. Maybe you know
some examples like this, but with load and stores?
It just seems weird to me that we already depend on very similar mechanics,
but this one seems like a bad idea.

Best
Piotr
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170407/07c0d0f2/attachment.html>


More information about the llvm-dev mailing list