[PATCH] D37419: Teach scalar evolution to handle inttoptr/ptrtoint

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 3 18:16:20 PDT 2017


On Sun, Sep 3, 2017 at 4:53 PM, Daniel Berlin <dberlin at dberlin.org> wrote:
>> > I also don't understand "  // It's tempting to handle inttoptr and
>> > ptrtoint
>> > as no-ops, however this can
>> >   // lead to pointer expressions which cannot safely be expanded to
>> > GEPs,
>> >   // because ScalarEvolution doesn't respect the GEP aliasing rules when
>> >   // simplifying integer expressions."
>> >
>> > 1. What are "the gep aliasing rules", exactly?
>> > https://llvm.org/docs/LangRef.html#pointeraliasing does not mention
>> > special
>> > rules for gep :)
>>
>> I think the rule it is talking about is that reads and writes on a GEP
>> are allowed to only read from and write to the allocation that is
>> passed in as the first parameter to the GEP
>
> When we had the discussion about "inrange" and "inbounds", (and elsewhere,
> like field accesses) it was raised repeatedly that it's just fine to gep
> outside what would be the normal "range" of a pointer, because you can't
> ever really tell what it is.
> IE a gep of a given pointer can access anything it wants.
>
> In fact, it seemed generally accepted that you can happily GEP from a
> pointer to anywhere you want unless there's an inrange or inbounds on it.

I think there are two issues here.

Non-inbounds GEPs to outside the base allocation is allowed by
themselves, and produce a bitwise value.  Inbounds GEPs to outside the
base allocation produces poison.

So this is allowed:

  %p0 = malloc(16);
  %p1 = malloc(16);
  %gep = gep i8* %p0, i64 18
  %cmp = icmp eq %gep, %p1
  br i1 %cmp, ...

but it would not be allowed if the GEP was inbounds (we'd be branching
on poison).

*However* (this is the "and issue reads/writes" bit in my previous
email) for reading / writing through the result of a GEP the GEP must
*also* follow the pointer aliasing rules.  Of course the GEP must not
have produced poison either, that's necessary but not sufficient for
safe memory operations.

> So i'm not sure what you mean by "the allocation", since none of these
> allocations are  defined in terms of llvm memory semantics (IE they aren't
> alloca's, they are malloc/frees).
> If that's not the case, we are not being consistent (IE we're losing
> optimizations we shouldn't, and we have correctness issues we don't think we
> do).

[snip]

> This set of rules, without anything more, implies we have both correcntess
> and optimization issues :)

The semantic in "pointer aliasing rules" is already implemented --
BasicAA returns NoAlias for %p1 and %gep even though @subtract could
have returned an offset that will guarantee that at runtime %p1 ==
%gep:

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

define void @f(i64 %arg, i64 %arg1) {
bb:
  %p0 = tail call noalias i8* @malloc(i64 %arg) #3
  %p1 = tail call noalias i8* @malloc(i64 %arg) #3
  %offset = tail call i64 @subtract(i8* %p1, i8* %p0)
  %gep = getelementptr i8, i8* %p0, i64 %offset  ;; not inbounds
  ret void
}

declare noalias i8* @malloc(i64)
declare i64 @subtract(i8*, i8*)
```

I believe this follows from the GetUnderlyingObject and
isIdentifiedObject related logic in  BasicAAResult::aliasCheck.

And I'm not aware of any transforms in LLVM today that contradict the
pointer aliasing rules.

-- Sanjoy


More information about the llvm-commits mailing list