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

whitequark via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 3 12:55:02 PDT 2016


whitequark added a comment.

I acknowledge that your analysis is correct, and I see your point about the transformations (assuming for sake of translation of your argument so that it translates to LICM that by `if(false)` you mean "a loop with zero trip count"). The core of the issue as I see it is that, when applied to self-contradictory IR, otherwise valid optimizations can bring undefined behavior "out of thin air".

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 }

The loop trip count is zero, and the second load is clearly undefined, but ToT LICM nevertheless hoists it.

Personally, I think that:

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.
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.


Repository:
  rL LLVM

http://reviews.llvm.org/D18738





More information about the llvm-commits mailing list