summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/LangRef.rst10
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp4
-rw-r--r--llvm/test/Transforms/InstSimplify/compare.ll23
3 files changed, 36 insertions, 1 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 96883a8090f..9e44705530a 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -5157,7 +5157,7 @@ Syntax:
::
- <result> = load [volatile] <ty>* <pointer>[, align <alignment>][, !nontemporal !<index>][, !invariant.load !<index>]
+ <result> = load [volatile] <ty>* <pointer>[, align <alignment>][, !nontemporal !<index>][, !invariant.load !<index>][, !nonnull !<index>]
<result> = load atomic [volatile] <ty>* <pointer> [singlethread] <ordering>, align <alignment>
!<index> = !{ i32 1 }
@@ -5213,6 +5213,14 @@ address points to memory which does not change value during program
execution. The optimizer may then move this load around, for example, by
hoisting it out of loops using loop invariant code motion.
+The optional ``!nonnull`` metadata must reference a single
+metadata name ``<index>`` corresponding to a metadata node with no
+entries. The existence of the ``!nonnull`` metadata on the
+instruction tells the optimizer that the value loaded is known to
+never be null. This is analogous to the ''nonnull'' attribute
+on parameters and return values. This metadata can only be applied
+to loads of a pointer type.
+
Semantics:
""""""""""
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 22f0486e8a2..462d5b7cf0b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2622,6 +2622,10 @@ bool llvm::isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI) {
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
return !GV->hasExternalWeakLinkage();
+ // A Load tagged w/nonnull metadata is never null.
+ if (const LoadInst *LI = dyn_cast<LoadInst>(V))
+ return LI->getMetadata("nonnull");
+
if (ImmutableCallSite CS = V)
if (CS.isReturnNonNull())
return true;
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index b30648301ae..38fd747172f 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -949,6 +949,29 @@ define i1 @returns_nonnull_as_deref() {
; CHECK: ret
}
+define i1 @nonnull_load(i32** %addr) {
+ %ptr = load i32** %addr, !nonnull !{}
+ %cmp = icmp eq i32* %ptr, null
+ ret i1 %cmp
+; CHECK-LABEL: @nonnull_load
+; CHECK: ret i1 false
+}
+
+define i1 @nonnull_load_as_outer(i32* addrspace(1)* %addr) {
+ %ptr = load i32* addrspace(1)* %addr, !nonnull !{}
+ %cmp = icmp eq i32* %ptr, null
+ ret i1 %cmp
+; CHECK-LABEL: @nonnull_load_as_outer
+; CHECK: ret i1 false
+}
+define i1 @nonnull_load_as_inner(i32 addrspace(1)** %addr) {
+ %ptr = load i32 addrspace(1)** %addr, !nonnull !{}
+ %cmp = icmp eq i32 addrspace(1)* %ptr, null
+ ret i1 %cmp
+; CHECK-LABEL: @nonnull_load_as_inner
+; CHECK: ret i1 false
+}
+
; If a bit is known to be zero for A and known to be one for B,
; then A and B cannot be equal.
define i1 @icmp_eq_const(i32 %a) nounwind {
OpenPOWER on IntegriCloud