A potential bug

Hi all,

There might be a bug in DeadStoreElimination.cpp. This pass eliminates stores backwards aggressively in an end BB. It does not check dependencies on stores in an end BB though. For example, in this code snippet:

  1. %sum.safe_r47.pre-phi = phi i64* [ %sum.safe_r47.pre, %entry.for.end_crit_edge ], [ %sum.safe_r42, %for.body ]
  2. %call9 = call i32 @gettimeofday(%struct.timeval* %end, %struct.timeval* null) nounwind
  3. %0 = bitcast %struct.timeval* %start to i64* // eliminated by HandleEndBlock in DeadStoreElimination.cpp
  4. %1 = bitcast %struct.timeval* %agg.tmp to i64* // eliminated …
  5. %tmp49 = load i64* %0, align 8 // eliminated …
  6. store i64 %tmp49, i64* %1, align 8 // eliminated …
  7. %2 = bitcast %struct.timeval* %end to i64* // eliminated …
  8. %3 = bitcast %struct.timeval* %agg.tmp12 to i64* // eliminated …
  9. %tmp50 = load i64* %2, align 8 // eliminated …
  10. store i64 %tmp50, i64* %3, align 8 // eliminated …
  11. %tv_sec = getelementptr inbounds %struct.timeval* %agg.tmp, i32 0, i32 0
  12. %tv_sec.safe_r = call i32* @llvm.guard.load.p0i32(i32* %tv_sec) // intrinsic function call inserted by me
  13. %tmp15 = load i32* %tv_sec.safe_r, align 4, !tbaa !4 // this loads the value stored at line 6
  14. %tv_usec = getelementptr inbounds %struct.timeval* %agg.tmp, i32 0, i32 1
  15. %tv_usec.safe_r = call i32* @llvm.guard.load.p0i32(i32* %tv_usec) // intrinsic function call …
  16. %tmp16 = load i32* %tv_usec.safe_r, align 4, !tbaa !4
  17. %tv_sec17 = getelementptr inbounds %struct.timeval* %agg.tmp12, i32 0, i32 0
  18. %tv_sec17.safe_r = call i32* @llvm.guard.load.p0i32(i32* %tv_sec17) // intrinsic function call …
  19. %tmp18 = load i32* %tv_sec17.safe_r, align 4, !tbaa !4
  20. %tv_usec19 = getelementptr inbounds %struct.timeval* %agg.tmp12, i32 0, i32 1
  21. %tv_usec19.safe_r = call i32* @llvm.guard.load.p0i32(i32* %tv_usec19) // intrinsic function call
  22. %tmp20 = load i32* %tv_usec19.safe_r, align 4, !tbaa !4
  23. %call21 = call i32 @delta(i32 %tmp15, i32 %tmp16, i32 %tmp18, i32 %tmp20)

It is compiled by clang 2.9. This BB is an end block in a function. Intrinsic function llvm.guard.load.p0i32 is defined as follows:
let Properties = [IntrNoMem, NoCapture<0>] in {
def int_guard_load : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>]>
}

Thanks a lot.
Bin

IntrNoMem means that your intrinsic doesn't access memory... I don't
think that is what you want.

-Eli

Well, either that or the NoCapture marking is wrong. What exactly is
your int_guard_load supposed to do?

-Eli

It does not do anything. It is an abstract function which transforms a pointer and returns another pointer of the same type. It does not visit memory or capture the pointer parameter.

If int_guard_load returns a pointer based on the passed-in pointer, it
captures it (at least according to the definition of "capture" which
NoCapture uses).

-Eli

So capture means if the function returns a pointer calculated with the passed pointer parameter or store somewhere a pointer calculated from the passed pointer? Thanks a lot, Eli.