diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2707,14 +2707,20 @@ return isKnownNonZero(I->getOperand(0), Depth, Q) && isGuaranteedNotToBePoison(I->getOperand(0), Q.AC, Q.CxtI, Q.DT, Depth); - case Instruction::Load: - // A Load tagged with nonnull metadata is never null. - if (Q.IIQ.getMetadata(cast(I), LLVMContext::MD_nonnull)) - return true; + case Instruction::Load: { + auto *LI = cast(I); + // A Load tagged with nonnull or dereferenceable with null pointer undefined + // is never null. + if (auto *PtrT = dyn_cast(I->getType())) + if (Q.IIQ.getMetadata(LI, LLVMContext::MD_nonnull) || + (Q.IIQ.getMetadata(LI, LLVMContext::MD_dereferenceable) && + !NullPointerIsDefined(LI->getFunction(), PtrT->getAddressSpace()))) + return true; // No need to fall through to computeKnownBits as range metadata is already // handled in isKnownNonZero. return false; + } case Instruction::Call: case Instruction::Invoke: if (I->getType()->isPointerTy()) { diff --git a/llvm/test/Transforms/InstSimplify/icmp.ll b/llvm/test/Transforms/InstSimplify/icmp.ll --- a/llvm/test/Transforms/InstSimplify/icmp.ll +++ b/llvm/test/Transforms/InstSimplify/icmp.ll @@ -258,3 +258,23 @@ %cmp = icmp ne i8 %sub, %x ret i1 %cmp } + +define i1 @load_ptr(ptr %p) { +; CHECK-LABEL: @load_ptr( +; CHECK-NEXT: ret i1 true +; + %load_p = load ptr, ptr %p, !dereferenceable !{i64 8} + %r = icmp ne ptr %load_p, null + ret i1 %r +} + +define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid { +; CHECK-LABEL: @load_ptr_null_valid( +; CHECK-NEXT: [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable !0 +; CHECK-NEXT: [[R:%.*]] = icmp ne ptr [[LOAD_P]], null +; CHECK-NEXT: ret i1 [[R]] +; + %load_p = load ptr, ptr %p, !dereferenceable !{i64 8} + %r = icmp ne ptr %load_p, null + ret i1 %r +}