[PATCH] D18738: Add new !unconditionally_dereferenceable load instruction metadata

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 3 13:22:05 PDT 2016


sanjoy added a comment.

In http://reviews.llvm.org/D18738#390734, @whitequark wrote:

>




> However, this is something that already happens in LLVM. Consider this testcase:

> 

>   target datalayout = "E-m:e-p:32:32-i8:8:8-i16:16:16-i64:32:32-f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32"

>   

>   %a = type { %b* }

>   %b = type { i32 }

>   

>   define void @test() {

>   entry:

>     %arg = alloca %a

>     %ptr.f = getelementptr inbounds %a, %a* %arg, i32 0, i32 0

>     %val.f = load %b*, %b** %ptr.f, !invariant.load !0, !dereferenceable !1

>     br label %for.head

>   

>   for.head:

>     %IND = phi i32 [ 0, %entry ], [ %IND.new, %for.body ]

>     %CMP = icmp slt i32 %IND, 0

>     br i1 %CMP, label %for.body, label %exit

>   

>   for.body:

>     %ptr.x = getelementptr inbounds %b, %b* %val.f, i32 0, i32 0

>     %val.x = load i32, i32* %ptr.x, !invariant.load !0

>     call void @consume(i32 %val.x)

>     %IND.new = add i32 %IND, 1

>     br label %for.head

>   

>   exit:

>     ret void

>   }

>   

>   declare void @consume(i32)

>   

>   !0 = !{}

>   !1 = !{ i64 4 }

> 


I may be missing the point here, but isn't the program undefined to
begin with?  `%val.f` is marked as `!dereferenceable` yet it results
in a non-dereferenceable value, and that breaks the frontend's
contract with the optimizer.  If I remove `!dereferenceable` from
`%val.f`, then LICM does not hoist the load out of the loop.

> 1. It is the responsibility of the frontend to not construct self-contradictory IR. There are far too many ways to do it that are not obviously wrong (and thus not easily rejected by the verifier), e.g. it is easy to do so with TBAA.


Agreed, if the frontend generates bogus IR then all bets are off.  The
IR verifier is only a best-effort sanity check, and cannot catch every
issue.

> 2. It is the responsibility of the middle-end to not construct self-contradictory IR when given non-self-contradictory IR. I.e. in your example the transformation introducing the code inside `if (false) { ... }` is clearly at fault, because there are some (dynamically dead) CFG paths that violate the invariants of the `!unconditionally_dereferenceable` marker and there were none before it.


But with `!unconditionally_dereferenceable`, this ("don't introduce
dynamically dead paths") is a //new// burden to the optimizer that
wasn't there before (as far as I can tell).  That is what I'm worried
about.

And there are cases where we'd realistically want to introduce
dynamically dead paths (indirectly).  E.g. imagine a sophisticated
"cold function merging" optimization, like:

  int* foo1(int** ptr) {
    int* val = **ptr, unconditionally_dereferenceable
    val;
  }
  
  int* foo2(int** ptr) {
    val = *ptr
    val;
  }
  
  void bar(int** ptr) {
    int* k1 = foo1(ptr);
    int* k2 = foo2(alloca(...));
  }

Non-existent (at present) function commoning pass =>

  int* foo_common(int** ptr, bool unconditional) {
    int *val;
    if (unconditional) {
      val = *ptr, unconditionally_dereferenceable
    } else {
      val = *ptr
    }
    return val;
  }
  
  void bar(int* ptr) {
    int* k1 = foo_common(ptr, true);
    int* k2 = foo_common(alloca(...), false);
  }

Inlining into bar =>

  void bar(int* ptr) {
    int* k1 = foo1(ptr, true);
    // inlined int* k2 = foo_common(alloca(...), false);
    t = alloca(...)
    int* val;
    if (false) {
      val = *ptr, unconditionally_dereferenceable
    } else {
      val = *ptr
    }
  }


Repository:
  rL LLVM

http://reviews.llvm.org/D18738





More information about the llvm-commits mailing list