[PATCH] D66664: [FIX] Nonnull is not always implied by dereferenceable

Johannes Doerfert via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 23 10:01:54 PDT 2019


jdoerfert created this revision.
jdoerfert added reviewers: reames, sanjoy, hfinkel, chandlerc, efriedma, lebedev.ri, fhahn.
Herald added subscribers: bollu, hiraditya, tpr.
Herald added a project: LLVM.

Depending on the function and address space nunnull is not implied by
dereferenceable. With this patch Value::getPointerDereferenceableBytes
will take into account that NULL might be a dereferenceable pointer.

This shows the problem and a solution but the TODO mentions how we
should actually go about it. See also D66618 <https://reviews.llvm.org/D66618>

This will also affect the following not yet patched tests:
 CodeGen/AMDGPU/legalize-fp-load-invariant.ll
 CodeGen/AMDGPU/parallelandifcollapse.ll
 Transforms/InstCombine/addrspacecast.ll
 Transforms/InstCombine/memcpy-addrspace.ll


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D66664

Files:
  llvm/lib/IR/Value.cpp
  llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll


Index: llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll
===================================================================
--- llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll
+++ llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll
@@ -51,10 +51,16 @@
     %sret_gep_outside = getelementptr %struct.A, %struct.A* %result, i64 0, i32 1, i64 7
     load i8, i8* %sret_gep_outside
 
-; CHECK: %dparam{{.*}}(aligned)
+; FIXME: This can be null but it is also known dereferenceable. However, right
+;        now we cannot return both information from
+;        Value::getPointerDereferenceableBytes(...).
+; CHECK-NOT: %dparam{{.*}}(aligned)
     %load3 = load i32, i32 addrspace(1)* %dparam
 
-; CHECK: %relocate{{.*}}(aligned)
+; FIXME: This can be null but it is also known dereferenceable. However, right
+;        now we cannot return both information from
+;        Value::getPointerDereferenceableBytes(...).
+; CHECK-NOT: %relocate{{.*}}(aligned)
     %tok = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam)
     %relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 7, i32 7)
     %load4 = load i32, i32 addrspace(1)* %relocate
@@ -106,8 +112,11 @@
     %load14 = load i8, i8* @globalptr.align16, align 16
 
     ; Loads from aligned arguments
-; CHECK: %dparam.align1{{.*}}(unaligned)
-; CHECK: %dparam.align16{{.*}}(aligned)
+; FIXME: This can be null but it is also known dereferenceable. However, right
+;        now we cannot return both information from
+;        Value::getPointerDereferenceableBytes(...).
+; CHECK-NOT: %dparam.align1{{.*}}(unaligned)
+; CHECK-NOT: %dparam.align16{{.*}}(aligned)
     %load15 = load i8, i8 addrspace(1)* %dparam.align1, align 16
     %load16 = load i8, i8 addrspace(1)* %dparam.align16, align 16
 
@@ -132,10 +141,13 @@
     %load18 = load i1, i1* %alloca.align16, align 16
 
     ; Loads from GEPs
-; CHECK: %gep.align1.offset1{{.*}}(unaligned)
-; CHECK: %gep.align16.offset1{{.*}}(unaligned)
-; CHECK: %gep.align1.offset16{{.*}}(unaligned)
-; CHECK: %gep.align16.offset16{{.*}}(aligned)
+; FIXME: This can be null but it is also known dereferenceable. However, right
+;        now we cannot return both information from
+;        Value::getPointerDereferenceableBytes(...).
+; CHECK-NOT: %gep.align1.offset1{{.*}}(unaligned)
+; CHECK-NOT: %gep.align16.offset1{{.*}}(unaligned)
+; CHECK-NOT: %gep.align1.offset16{{.*}}(unaligned)
+; CHECK-NOT: %gep.align16.offset16{{.*}}(aligned)
     %gep.align1.offset1 = getelementptr inbounds i8, i8 addrspace(1)* %dparam.align1, i32 1
     %gep.align16.offset1 = getelementptr inbounds i8, i8 addrspace(1)* %dparam.align16, i32 1
     %gep.align1.offset16 = getelementptr inbounds i8, i8 addrspace(1)* %dparam.align1, i32 16
Index: llvm/lib/IR/Value.cpp
===================================================================
--- llvm/lib/IR/Value.cpp
+++ llvm/lib/IR/Value.cpp
@@ -613,9 +613,14 @@
                                                bool &CanBeNull) const {
   assert(getType()->isPointerTy() && "must be pointer");
 
+  const Function *F = nullptr;
+  if (auto *I = dyn_cast<Instruction>(this))
+    F = I->getFunction();
+
   uint64_t DerefBytes = 0;
   CanBeNull = false;
   if (const Argument *A = dyn_cast<Argument>(this)) {
+    F = A->getParent();
     DerefBytes = A->getDereferenceableBytes();
     if (DerefBytes == 0 && (A->hasByValAttr() || A->hasStructRetAttr())) {
       Type *PT = cast<PointerType>(A->getType())->getElementType();
@@ -672,6 +677,12 @@
       CanBeNull = false;
     }
   }
+
+  // Even if we know it is "dereferenceable", it can still be null if null is a
+  // valid pointer. This is a problem as "can be null" is overloaded to mean,
+  // "equals NULL" and "or is not dereferenceable".
+  // TODO: Add a separate flag to communicate "IsKnownDeref".
+  CanBeNull |= NullPointerIsDefined(F, getType()->getPointerAddressSpace());
   return DerefBytes;
 }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D66664.216880.patch
Type: text/x-patch
Size: 4078 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190823/5adc43d8/attachment.bin>


More information about the llvm-commits mailing list