[llvm] r336613 - llvm: Add support for "-fno-delete-null-pointer-checks"

Manoj Gupta via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 9 15:27:23 PDT 2018


Author: manojgupta
Date: Mon Jul  9 15:27:23 2018
New Revision: 336613

URL: http://llvm.org/viewvc/llvm-project?rev=336613&view=rev
Log:
llvm: Add support for "-fno-delete-null-pointer-checks"

Summary:
Support for this option is needed for building Linux kernel.
This is a very frequently requested feature by kernel developers.

More details : https://lkml.org/lkml/2018/4/4/601

GCC option description for -fdelete-null-pointer-checks:
This Assume that programs cannot safely dereference null pointers,
and that no code or data element resides at address zero.

-fno-delete-null-pointer-checks is the inverse of this implying that
null pointer dereferencing is not undefined.

This feature is implemented in LLVM IR in this CL as the function attribute
"null-pointer-is-valid"="true" in IR (Under review at D47894).
The CL updates several passes that assumed null pointer dereferencing is
undefined to not optimize when the "null-pointer-is-valid"="true"
attribute is present.

Reviewers: t.p.northover, efriedma, jyknight, chandlerc, rnk, srhines, void, george.burgess.iv

Reviewed By: efriedma, george.burgess.iv

Subscribers: eraman, haicheng, george.burgess.iv, drinkcat, theraven, reames, sanjoy, xbolva00, llvm-commits

Differential Revision: https://reviews.llvm.org/D47895

Added:
    llvm/trunk/test/Transforms/GVN/PRE/2018-06-08-pre-load-dbgloc-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll
    llvm/trunk/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll
    llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll
    llvm/trunk/test/Transforms/SimplifyCFG/trap-no-null-opt-debugloc.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/Analysis/BasicAliasAnalysis.h
    llvm/trunk/include/llvm/IR/CallSite.h
    llvm/trunk/include/llvm/IR/Function.h
    llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
    llvm/trunk/lib/Analysis/ConstantFolding.cpp
    llvm/trunk/lib/Analysis/InlineCost.cpp
    llvm/trunk/lib/Analysis/InstructionSimplify.cpp
    llvm/trunk/lib/Analysis/LazyValueInfo.cpp
    llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp
    llvm/trunk/lib/Analysis/ValueTracking.cpp
    llvm/trunk/lib/IR/ConstantFold.cpp
    llvm/trunk/lib/IR/Function.cpp
    llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
    llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
    llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
    llvm/trunk/lib/Transforms/Utils/Local.cpp
    llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
    llvm/trunk/test/Analysis/MemorySSA/cyclicphi.ll
    llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4.ll
    llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi.ll
    llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1.ll
    llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2.ll
    llvm/trunk/test/Transforms/IPConstantProp/PR26044.ll
    llvm/trunk/test/Transforms/Inline/attributes.ll
    llvm/trunk/test/Transforms/InstCombine/atomic.ll
    llvm/trunk/test/Transforms/InstCombine/invariant.group.ll
    llvm/trunk/test/Transforms/InstCombine/invoke.ll
    llvm/trunk/test/Transforms/InstCombine/load.ll
    llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll
    llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll
    llvm/trunk/test/Transforms/InstCombine/select.ll
    llvm/trunk/test/Transforms/InstCombine/store.ll
    llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll
    llvm/trunk/test/Transforms/InstCombine/strlen-1.ll
    llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll
    llvm/trunk/test/Transforms/InstSimplify/compare.ll
    llvm/trunk/test/Transforms/LoopIdiom/pr28196.ll
    llvm/trunk/test/Transforms/LoopVersioning/lcssa.ll
    llvm/trunk/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
    llvm/trunk/test/Transforms/SimplifyCFG/invoke.ll
    llvm/trunk/test/Transforms/SimplifyCFG/phi-undef-loadstore.ll
    llvm/trunk/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll
    llvm/trunk/unittests/Analysis/AliasAnalysisTest.cpp
    llvm/trunk/unittests/Analysis/MemorySSA.cpp

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Mon Jul  9 15:27:23 2018
@@ -1461,6 +1461,14 @@ example:
     trap or generate asynchronous exceptions. Exception handling schemes
     that are recognized by LLVM to handle asynchronous exceptions, such
     as SEH, will still provide their implementation defined semantics.
+``"null-pointer-is-valid"``
+   If ``"null-pointer-is-valid"`` is set to ``"true"``, then ``null`` address
+   in address-space 0 is considered to be a valid address for memory loads and
+   stores. Any analysis or optimization should not treat dereferencing a
+   pointer to ``null`` as undefined behavior in this function.
+   Note: Comparing address of a global variable to ``null`` may still
+   evaluate to false because of a limitation in querying this attribute inside
+   constant expressions.
 ``optforfuzzing``
     This attribute indicates that this function should be optimized
     for maximum fuzzing signal.

Modified: llvm/trunk/include/llvm/Analysis/BasicAliasAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/BasicAliasAnalysis.h?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/BasicAliasAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/BasicAliasAnalysis.h Mon Jul  9 15:27:23 2018
@@ -55,26 +55,27 @@ class BasicAAResult : public AAResultBas
   friend AAResultBase<BasicAAResult>;
 
   const DataLayout &DL;
+  const Function &F;
   const TargetLibraryInfo &TLI;
   AssumptionCache &AC;
   DominatorTree *DT;
   LoopInfo *LI;
 
 public:
-  BasicAAResult(const DataLayout &DL, const TargetLibraryInfo &TLI,
-                AssumptionCache &AC, DominatorTree *DT = nullptr,
-                LoopInfo *LI = nullptr)
-      : AAResultBase(), DL(DL), TLI(TLI), AC(AC), DT(DT), LI(LI) {}
+  BasicAAResult(const DataLayout &DL, const Function &F,
+                const TargetLibraryInfo &TLI, AssumptionCache &AC,
+                DominatorTree *DT = nullptr, LoopInfo *LI = nullptr)
+      : AAResultBase(), DL(DL), F(F), TLI(TLI), AC(AC), DT(DT), LI(LI) {}
 
   BasicAAResult(const BasicAAResult &Arg)
-      : AAResultBase(Arg), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT),
-        LI(Arg.LI) {}
-  BasicAAResult(BasicAAResult &&Arg)
-      : AAResultBase(std::move(Arg)), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC),
+      : AAResultBase(Arg), DL(Arg.DL), F(Arg.F), TLI(Arg.TLI), AC(Arg.AC),
         DT(Arg.DT), LI(Arg.LI) {}
+  BasicAAResult(BasicAAResult &&Arg)
+      : AAResultBase(std::move(Arg)), DL(Arg.DL), F(Arg.F), TLI(Arg.TLI),
+        AC(Arg.AC), DT(Arg.DT), LI(Arg.LI) {}
 
   /// Handle invalidation events in the new pass manager.
-  bool invalidate(Function &F, const PreservedAnalyses &PA,
+  bool invalidate(Function &Fn, const PreservedAnalyses &PA,
                   FunctionAnalysisManager::Invalidator &Inv);
 
   AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
@@ -94,7 +95,7 @@ public:
 
   /// Returns the behavior when calling the given function. For use when the
   /// call site is not known.
-  FunctionModRefBehavior getModRefBehavior(const Function *F);
+  FunctionModRefBehavior getModRefBehavior(const Function *Fn);
 
 private:
   // A linear transformation of a Value; this class represents ZExt(SExt(V,

Modified: llvm/trunk/include/llvm/IR/CallSite.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/CallSite.h?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/CallSite.h (original)
+++ llvm/trunk/include/llvm/IR/CallSite.h Mon Jul  9 15:27:23 2018
@@ -637,7 +637,8 @@ public:
     if (hasRetAttr(Attribute::NonNull))
       return true;
     else if (getDereferenceableBytes(AttributeList::ReturnIndex) > 0 &&
-             getType()->getPointerAddressSpace() == 0)
+             !NullPointerIsDefined(getCaller(),
+                                   getType()->getPointerAddressSpace()))
       return true;
 
     return false;

Modified: llvm/trunk/include/llvm/IR/Function.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Function.h?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Function.h (original)
+++ llvm/trunk/include/llvm/IR/Function.h Mon Jul  9 15:27:23 2018
@@ -781,6 +781,12 @@ public:
   /// Returns true if we should emit debug info for profiling.
   bool isDebugInfoForProfiling() const;
 
+  /// Check if null pointer dereferencing is considered undefined behavior for
+  /// the function.
+  /// Return value: false => null pointer dereference is undefined.
+  /// Return value: true =>  null pointer dereference is not undefined.
+  bool nullPointerIsDefined() const;
+
 private:
   void allocHungoffUselist();
   template<int Idx> void setHungoffOperand(Constant *C);
@@ -793,6 +799,13 @@ private:
   void setValueSubclassDataBit(unsigned Bit, bool On);
 };
 
+/// Check whether null pointer dereferencing is considered undefined behavior
+/// for a given function or an address space.
+/// Null pointer access in non-zero address space is not considered undefined.
+/// Return value: false => null pointer dereference is undefined.
+/// Return value: true =>  null pointer dereference is not undefined.
+bool NullPointerIsDefined(const Function *F, unsigned AS = 0);
+
 template <>
 struct OperandTraits<Function> : public HungoffOperandTraits<3> {};
 

Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Mon Jul  9 15:27:23 2018
@@ -85,15 +85,15 @@ const unsigned MaxNumPhiBBsValueReachabi
 // depth otherwise the algorithm in aliasGEP will assert.
 static const unsigned MaxLookupSearchDepth = 6;
 
-bool BasicAAResult::invalidate(Function &F, const PreservedAnalyses &PA,
+bool BasicAAResult::invalidate(Function &Fn, const PreservedAnalyses &PA,
                                FunctionAnalysisManager::Invalidator &Inv) {
   // We don't care if this analysis itself is preserved, it has no state. But
   // we need to check that the analyses it depends on have been. Note that we
   // may be created without handles to some analyses and in that case don't
   // depend on them.
-  if (Inv.invalidate<AssumptionAnalysis>(F, PA) ||
-      (DT && Inv.invalidate<DominatorTreeAnalysis>(F, PA)) ||
-      (LI && Inv.invalidate<LoopAnalysis>(F, PA)))
+  if (Inv.invalidate<AssumptionAnalysis>(Fn, PA) ||
+      (DT && Inv.invalidate<DominatorTreeAnalysis>(Fn, PA)) ||
+      (LI && Inv.invalidate<LoopAnalysis>(Fn, PA)))
     return true;
 
   // Otherwise this analysis result remains valid.
@@ -150,10 +150,12 @@ static bool isEscapeSource(const Value *
 /// Returns the size of the object specified by V or UnknownSize if unknown.
 static uint64_t getObjectSize(const Value *V, const DataLayout &DL,
                               const TargetLibraryInfo &TLI,
+                              bool NullIsValidLoc,
                               bool RoundToAlign = false) {
   uint64_t Size;
   ObjectSizeOpts Opts;
   Opts.RoundToAlign = RoundToAlign;
+  Opts.NullIsUnknownSize = NullIsValidLoc;
   if (getObjectSize(V, Size, DL, &TLI, Opts))
     return Size;
   return MemoryLocation::UnknownSize;
@@ -163,7 +165,8 @@ static uint64_t getObjectSize(const Valu
 /// Size.
 static bool isObjectSmallerThan(const Value *V, uint64_t Size,
                                 const DataLayout &DL,
-                                const TargetLibraryInfo &TLI) {
+                                const TargetLibraryInfo &TLI,
+                                bool NullIsValidLoc) {
   // Note that the meanings of the "object" are slightly different in the
   // following contexts:
   //    c1: llvm::getObjectSize()
@@ -195,15 +198,16 @@ static bool isObjectSmallerThan(const Va
 
   // This function needs to use the aligned object size because we allow
   // reads a bit past the end given sufficient alignment.
-  uint64_t ObjectSize = getObjectSize(V, DL, TLI, /*RoundToAlign*/ true);
+  uint64_t ObjectSize = getObjectSize(V, DL, TLI, NullIsValidLoc,
+                                      /*RoundToAlign*/ true);
 
   return ObjectSize != MemoryLocation::UnknownSize && ObjectSize < Size;
 }
 
 /// Returns true if we can prove that the object specified by V has size Size.
 static bool isObjectSize(const Value *V, uint64_t Size, const DataLayout &DL,
-                         const TargetLibraryInfo &TLI) {
-  uint64_t ObjectSize = getObjectSize(V, DL, TLI);
+                         const TargetLibraryInfo &TLI, bool NullIsValidLoc) {
+  uint64_t ObjectSize = getObjectSize(V, DL, TLI, NullIsValidLoc);
   return ObjectSize != MemoryLocation::UnknownSize && ObjectSize == Size;
 }
 
@@ -1623,10 +1627,10 @@ AliasResult BasicAAResult::aliasCheck(co
   // Null values in the default address space don't point to any object, so they
   // don't alias any other pointer.
   if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O1))
-    if (CPN->getType()->getAddressSpace() == 0)
+    if (!NullPointerIsDefined(&F, CPN->getType()->getAddressSpace()))
       return NoAlias;
   if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O2))
-    if (CPN->getType()->getAddressSpace() == 0)
+    if (!NullPointerIsDefined(&F, CPN->getType()->getAddressSpace()))
       return NoAlias;
 
   if (O1 != O2) {
@@ -1662,10 +1666,11 @@ AliasResult BasicAAResult::aliasCheck(co
 
   // If the size of one access is larger than the entire object on the other
   // side, then we know such behavior is undefined and can assume no alias.
+  bool NullIsValidLocation = NullPointerIsDefined(&F);
   if ((V1Size != MemoryLocation::UnknownSize &&
-       isObjectSmallerThan(O2, V1Size, DL, TLI)) ||
+       isObjectSmallerThan(O2, V1Size, DL, TLI, NullIsValidLocation)) ||
       (V2Size != MemoryLocation::UnknownSize &&
-       isObjectSmallerThan(O1, V2Size, DL, TLI)))
+       isObjectSmallerThan(O1, V2Size, DL, TLI, NullIsValidLocation)))
     return NoAlias;
 
   // Check the cache before climbing up use-def chains. This also terminates
@@ -1725,8 +1730,8 @@ AliasResult BasicAAResult::aliasCheck(co
   if (O1 == O2)
     if (V1Size != MemoryLocation::UnknownSize &&
         V2Size != MemoryLocation::UnknownSize &&
-        (isObjectSize(O1, V1Size, DL, TLI) ||
-         isObjectSize(O2, V2Size, DL, TLI)))
+        (isObjectSize(O1, V1Size, DL, TLI, NullIsValidLocation) ||
+         isObjectSize(O2, V2Size, DL, TLI, NullIsValidLocation)))
       return AliasCache[Locs] = PartialAlias;
 
   // Recurse back into the best AA results we have, potentially with refined
@@ -1870,6 +1875,7 @@ AnalysisKey BasicAA::Key;
 
 BasicAAResult BasicAA::run(Function &F, FunctionAnalysisManager &AM) {
   return BasicAAResult(F.getParent()->getDataLayout(),
+                       F,
                        AM.getResult<TargetLibraryAnalysis>(F),
                        AM.getResult<AssumptionAnalysis>(F),
                        &AM.getResult<DominatorTreeAnalysis>(F),
@@ -1902,7 +1908,7 @@ bool BasicAAWrapperPass::runOnFunction(F
   auto &DTWP = getAnalysis<DominatorTreeWrapperPass>();
   auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>();
 
-  Result.reset(new BasicAAResult(F.getParent()->getDataLayout(), TLIWP.getTLI(),
+  Result.reset(new BasicAAResult(F.getParent()->getDataLayout(), F, TLIWP.getTLI(),
                                  ACT.getAssumptionCache(F), &DTWP.getDomTree(),
                                  LIWP ? &LIWP->getLoopInfo() : nullptr));
 
@@ -1919,6 +1925,7 @@ void BasicAAWrapperPass::getAnalysisUsag
 BasicAAResult llvm::createLegacyPMBasicAAResult(Pass &P, Function &F) {
   return BasicAAResult(
       F.getParent()->getDataLayout(),
+      F,
       P.getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(),
       P.getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F));
 }

Modified: llvm/trunk/lib/Analysis/ConstantFolding.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ConstantFolding.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ConstantFolding.cpp (original)
+++ llvm/trunk/lib/Analysis/ConstantFolding.cpp Mon Jul  9 15:27:23 2018
@@ -1589,7 +1589,8 @@ double getValueAsDouble(ConstantFP *Op)
 
 Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
                                  ArrayRef<Constant *> Operands,
-                                 const TargetLibraryInfo *TLI) {
+                                 const TargetLibraryInfo *TLI,
+                                 ImmutableCallSite CS) {
   if (Operands.size() == 1) {
     if (isa<UndefValue>(Operands[0])) {
       // cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN
@@ -1603,7 +1604,8 @@ Constant *ConstantFoldScalarCall(StringR
     }
 
     if (isa<ConstantPointerNull>(Operands[0]) &&
-        Operands[0]->getType()->getPointerAddressSpace() == 0) {
+        !NullPointerIsDefined(
+            CS.getCaller(), Operands[0]->getType()->getPointerAddressSpace())) {
       // launder(null) == null == strip(null) iff in addrspace 0
       if (IntrinsicID == Intrinsic::launder_invariant_group ||
           IntrinsicID == Intrinsic::strip_invariant_group)
@@ -2007,7 +2009,8 @@ Constant *ConstantFoldScalarCall(StringR
 Constant *ConstantFoldVectorCall(StringRef Name, unsigned IntrinsicID,
                                  VectorType *VTy, ArrayRef<Constant *> Operands,
                                  const DataLayout &DL,
-                                 const TargetLibraryInfo *TLI) {
+                                 const TargetLibraryInfo *TLI,
+                                 ImmutableCallSite CS) {
   SmallVector<Constant *, 4> Result(VTy->getNumElements());
   SmallVector<Constant *, 4> Lane(Operands.size());
   Type *Ty = VTy->getElementType();
@@ -2070,7 +2073,7 @@ Constant *ConstantFoldVectorCall(StringR
     }
 
     // Use the regular scalar folding to simplify this column.
-    Constant *Folded = ConstantFoldScalarCall(Name, IntrinsicID, Ty, Lane, TLI);
+    Constant *Folded = ConstantFoldScalarCall(Name, IntrinsicID, Ty, Lane, TLI, CS);
     if (!Folded)
       return nullptr;
     Result[I] = Folded;
@@ -2095,9 +2098,9 @@ llvm::ConstantFoldCall(ImmutableCallSite
 
   if (auto *VTy = dyn_cast<VectorType>(Ty))
     return ConstantFoldVectorCall(Name, F->getIntrinsicID(), VTy, Operands,
-                                  F->getParent()->getDataLayout(), TLI);
+                                  F->getParent()->getDataLayout(), TLI, CS);
 
-  return ConstantFoldScalarCall(Name, F->getIntrinsicID(), Ty, Operands, TLI);
+  return ConstantFoldScalarCall(Name, F->getIntrinsicID(), Ty, Operands, TLI, CS);
 }
 
 bool llvm::isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI) {

Modified: llvm/trunk/lib/Analysis/InlineCost.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InlineCost.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InlineCost.cpp (original)
+++ llvm/trunk/lib/Analysis/InlineCost.cpp Mon Jul  9 15:27:23 2018
@@ -1994,6 +1994,11 @@ InlineCost llvm::getInlineCost(
   if (Caller->hasFnAttribute(Attribute::OptimizeNone))
     return llvm::InlineCost::getNever();
 
+  // Don't inline a function that treats null pointer as valid into a caller
+  // that does not have this attribute.
+  if (!Caller->nullPointerIsDefined() && Callee->nullPointerIsDefined())
+    return llvm::InlineCost::getNever();
+
   // Don't inline functions which can be interposed at link-time.  Don't inline
   // functions marked noinline or call sites marked noinline.
   // Note: inlining non-exact non-interposable functions is fine, since we know

Modified: llvm/trunk/lib/Analysis/InstructionSimplify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InstructionSimplify.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InstructionSimplify.cpp (original)
+++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp Mon Jul  9 15:27:23 2018
@@ -2120,9 +2120,12 @@ computePointerICmp(const DataLayout &DL,
       ConstantInt *LHSOffsetCI = dyn_cast<ConstantInt>(LHSOffset);
       ConstantInt *RHSOffsetCI = dyn_cast<ConstantInt>(RHSOffset);
       uint64_t LHSSize, RHSSize;
+      ObjectSizeOpts Opts;
+      Opts.NullIsUnknownSize =
+          NullPointerIsDefined(cast<AllocaInst>(LHS)->getFunction());
       if (LHSOffsetCI && RHSOffsetCI &&
-          getObjectSize(LHS, LHSSize, DL, TLI) &&
-          getObjectSize(RHS, RHSSize, DL, TLI)) {
+          getObjectSize(LHS, LHSSize, DL, TLI, Opts) &&
+          getObjectSize(RHS, RHSSize, DL, TLI, Opts)) {
         const APInt &LHSOffsetValue = LHSOffsetCI->getValue();
         const APInt &RHSOffsetValue = RHSOffsetCI->getValue();
         if (!LHSOffsetValue.isNegative() &&

Modified: llvm/trunk/lib/Analysis/LazyValueInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyValueInfo.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LazyValueInfo.cpp (original)
+++ llvm/trunk/lib/Analysis/LazyValueInfo.cpp Mon Jul  9 15:27:23 2018
@@ -704,9 +704,11 @@ bool LazyValueInfoImpl::solveBlockValueN
     assert(isa<Argument>(Val) && "Unknown live-in to the entry block");
     // Before giving up, see if we can prove the pointer non-null local to
     // this particular block.
-    if (Val->getType()->isPointerTy() &&
-        (isKnownNonZero(Val, DL) || isObjectDereferencedInBlock(Val, BB))) {
-      PointerType *PTy = cast<PointerType>(Val->getType());
+    PointerType *PTy = dyn_cast<PointerType>(Val->getType());
+    if (PTy &&
+        (isKnownNonZero(Val, DL) ||
+          (isObjectDereferencedInBlock(Val, BB) &&
+           !NullPointerIsDefined(BB->getParent(), PTy->getAddressSpace())))) {
       Result = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
     } else {
       Result = ValueLatticeElement::getOverdefined();
@@ -739,9 +741,9 @@ bool LazyValueInfoImpl::solveBlockValueN
                         << "' - overdefined because of pred (non local).\n");
       // Before giving up, see if we can prove the pointer non-null local to
       // this particular block.
-      if (Val->getType()->isPointerTy() &&
-          isObjectDereferencedInBlock(Val, BB)) {
-        PointerType *PTy = cast<PointerType>(Val->getType());
+      PointerType *PTy = dyn_cast<PointerType>(Val->getType());
+      if (PTy && isObjectDereferencedInBlock(Val, BB) &&
+          !NullPointerIsDefined(BB->getParent(), PTy->getAddressSpace())) {
         Result = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
       }
 

Modified: llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp Mon Jul  9 15:27:23 2018
@@ -500,11 +500,11 @@ public:
   typedef PointerIntPair<Value *, 1, bool> MemAccessInfo;
   typedef SmallVector<MemAccessInfo, 8> MemAccessInfoList;
 
-  AccessAnalysis(const DataLayout &Dl, AliasAnalysis *AA, LoopInfo *LI,
-                 MemoryDepChecker::DepCandidates &DA,
+  AccessAnalysis(const DataLayout &Dl, Loop *TheLoop, AliasAnalysis *AA,
+                 LoopInfo *LI, MemoryDepChecker::DepCandidates &DA,
                  PredicatedScalarEvolution &PSE)
-      : DL(Dl), AST(*AA), LI(LI), DepCands(DA), IsRTCheckAnalysisNeeded(false),
-        PSE(PSE) {}
+      : DL(Dl), TheLoop(TheLoop), AST(*AA), LI(LI), DepCands(DA),
+        IsRTCheckAnalysisNeeded(false), PSE(PSE) {}
 
   /// Register a load  and whether it is only read from.
   void addLoad(MemoryLocation &Loc, bool IsReadOnly) {
@@ -579,6 +579,9 @@ private:
 
   const DataLayout &DL;
 
+  /// The loop being checked.
+  const Loop *TheLoop;
+
   /// List of accesses that need a further dependence check.
   MemAccessInfoList CheckDeps;
 
@@ -910,7 +913,10 @@ void AccessAnalysis::processMemAccesses(
           for (Value *UnderlyingObj : TempObjects) {
             // nullptr never alias, don't join sets for pointer that have "null"
             // in their UnderlyingObjects list.
-            if (isa<ConstantPointerNull>(UnderlyingObj))
+            if (isa<ConstantPointerNull>(UnderlyingObj) &&
+                !NullPointerIsDefined(
+                    TheLoop->getHeader()->getParent(),
+                    UnderlyingObj->getType()->getPointerAddressSpace()))
               continue;
 
             UnderlyingObjToAccessMap::iterator Prev =
@@ -1026,8 +1032,9 @@ int64_t llvm::getPtrStride(PredicatedSca
   bool IsNoWrapAddRec = !ShouldCheckWrap ||
     PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW) ||
     isNoWrapAddRec(Ptr, AR, PSE, Lp);
-  bool IsInAddressSpaceZero = PtrTy->getAddressSpace() == 0;
-  if (!IsNoWrapAddRec && !IsInBoundsGEP && !IsInAddressSpaceZero) {
+  if (!IsNoWrapAddRec && !IsInBoundsGEP &&
+      NullPointerIsDefined(Lp->getHeader()->getParent(),
+                           PtrTy->getAddressSpace())) {
     if (Assume) {
       PSE.setNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW);
       IsNoWrapAddRec = true;
@@ -1073,8 +1080,9 @@ int64_t llvm::getPtrStride(PredicatedSca
   // If the SCEV could wrap but we have an inbounds gep with a unit stride we
   // know we can't "wrap around the address space". In case of address space
   // zero we know that this won't happen without triggering undefined behavior.
-  if (!IsNoWrapAddRec && (IsInBoundsGEP || IsInAddressSpaceZero) &&
-      Stride != 1 && Stride != -1) {
+  if (!IsNoWrapAddRec && Stride != 1 && Stride != -1 &&
+      (IsInBoundsGEP || !NullPointerIsDefined(Lp->getHeader()->getParent(),
+                                              PtrTy->getAddressSpace()))) {
     if (Assume) {
       // We can avoid this case by adding a run-time check.
       LLVM_DEBUG(dbgs() << "LAA: Non unit strided pointer which is not either "
@@ -1845,7 +1853,7 @@ void LoopAccessInfo::analyzeLoop(AliasAn
 
   MemoryDepChecker::DepCandidates DependentAccesses;
   AccessAnalysis Accesses(TheLoop->getHeader()->getModule()->getDataLayout(),
-                          AA, LI, DependentAccesses, *PSE);
+                          TheLoop, AA, LI, DependentAccesses, *PSE);
 
   // Holds the analyzed pointers. We don't want to call GetUnderlyingObjects
   // multiple times on the same object. If the ptr is accessed twice, once

Modified: llvm/trunk/lib/Analysis/ValueTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ValueTracking.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ValueTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/ValueTracking.cpp Mon Jul  9 15:27:23 2018
@@ -1769,7 +1769,12 @@ bool isKnownToBeAPowerOfTwo(const Value
 /// Currently this routine does not support vector GEPs.
 static bool isGEPKnownNonNull(const GEPOperator *GEP, unsigned Depth,
                               const Query &Q) {
-  if (!GEP->isInBounds() || GEP->getPointerAddressSpace() != 0)
+  const Function *F = nullptr;
+  if (const Instruction *I = dyn_cast<Instruction>(GEP))
+    F = I->getFunction();
+
+  if (!GEP->isInBounds() ||
+      NullPointerIsDefined(F, GEP->getPointerAddressSpace()))
     return false;
 
   // FIXME: Support vector-GEPs.

Modified: llvm/trunk/lib/IR/ConstantFold.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ConstantFold.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/IR/ConstantFold.cpp (original)
+++ llvm/trunk/lib/IR/ConstantFold.cpp Mon Jul  9 15:27:23 2018
@@ -1500,8 +1500,12 @@ static ICmpInst::Predicate evaluateICmpR
       assert(isa<ConstantPointerNull>(V2) && "Canonicalization guarantee!");
       // GlobalVals can never be null unless they have external weak linkage.
       // We don't try to evaluate aliases here.
+      // NOTE: We should not be doing this constant folding if null pointer
+      // is considered valid for the function. But currently there is no way to
+      // query it from the Constant type.
       if (!GV->hasExternalWeakLinkage() && !isa<GlobalAlias>(GV) &&
-          GV->getType()->getAddressSpace() == 0)
+          !NullPointerIsDefined(nullptr /* F */,
+                                GV->getType()->getAddressSpace()))
         return ICmpInst::ICMP_NE;
     }
   } else if (const BlockAddress *BA = dyn_cast<BlockAddress>(V1)) {
@@ -1731,7 +1735,8 @@ Constant *llvm::ConstantFoldCompareInstr
     if (const GlobalValue *GV = dyn_cast<GlobalValue>(C2))
       // Don't try to evaluate aliases.  External weak GV can be null.
       if (!isa<GlobalAlias>(GV) && !GV->hasExternalWeakLinkage() &&
-          GV->getType()->getAddressSpace() == 0) {
+          !NullPointerIsDefined(nullptr /* F */,
+                                GV->getType()->getAddressSpace())) {
         if (pred == ICmpInst::ICMP_EQ)
           return ConstantInt::getFalse(C1->getContext());
         else if (pred == ICmpInst::ICMP_NE)
@@ -1742,7 +1747,8 @@ Constant *llvm::ConstantFoldCompareInstr
     if (const GlobalValue *GV = dyn_cast<GlobalValue>(C1))
       // Don't try to evaluate aliases.  External weak GV can be null.
       if (!isa<GlobalAlias>(GV) && !GV->hasExternalWeakLinkage() &&
-          GV->getType()->getAddressSpace() == 0) {
+          !NullPointerIsDefined(nullptr /* F */,
+                                GV->getType()->getAddressSpace())) {
         if (pred == ICmpInst::ICMP_EQ)
           return ConstantInt::getFalse(C1->getContext());
         else if (pred == ICmpInst::ICMP_NE)

Modified: llvm/trunk/lib/IR/Function.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Function.cpp (original)
+++ llvm/trunk/lib/IR/Function.cpp Mon Jul  9 15:27:23 2018
@@ -79,7 +79,8 @@ bool Argument::hasNonNullAttr() const {
   if (getParent()->hasParamAttribute(getArgNo(), Attribute::NonNull))
     return true;
   else if (getDereferenceableBytes() > 0 &&
-           getType()->getPointerAddressSpace() == 0)
+           !NullPointerIsDefined(getParent(),
+                                 getType()->getPointerAddressSpace()))
     return true;
   return false;
 }
@@ -1415,3 +1416,19 @@ Optional<StringRef> Function::getSection
   }
   return None;
 }
+
+bool Function::nullPointerIsDefined() const {
+  return getFnAttribute("null-pointer-is-valid")
+          .getValueAsString()
+          .equals("true");
+}
+
+bool llvm::NullPointerIsDefined(const Function *F, unsigned AS) {
+  if (F && F->nullPointerIsDefined())
+    return true;
+
+  if (AS != 0)
+    return true;
+
+  return false;
+}

Modified: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp Mon Jul  9 15:27:23 2018
@@ -636,7 +636,13 @@ static GlobalVariable *SRAGlobal(GlobalV
 /// reprocessing them.
 static bool AllUsesOfValueWillTrapIfNull(const Value *V,
                                         SmallPtrSetImpl<const PHINode*> &PHIs) {
-  for (const User *U : V->users())
+  for (const User *U : V->users()) {
+    if (const Instruction *I = dyn_cast<Instruction>(U)) {
+      // If null pointer is considered valid, then all uses are non-trapping.
+      // Non address-space 0 globals have already been pruned by the caller.
+      if (NullPointerIsDefined(I->getFunction()))
+        return false;
+    }
     if (isa<LoadInst>(U)) {
       // Will trap.
     } else if (const StoreInst *SI = dyn_cast<StoreInst>(U)) {
@@ -670,7 +676,7 @@ static bool AllUsesOfValueWillTrapIfNull
       //cerr << "NONTRAPPING USE: " << *U;
       return false;
     }
-
+  }
   return true;
 }
 
@@ -697,6 +703,10 @@ static bool OptimizeAwayTrappingUsesOfVa
   bool Changed = false;
   for (auto UI = V->user_begin(), E = V->user_end(); UI != E; ) {
     Instruction *I = cast<Instruction>(*UI++);
+    // Uses are non-trapping if null pointer is considered valid.
+    // Non address-space 0 globals are already pruned by the caller.
+    if (NullPointerIsDefined(I->getFunction()))
+      return false;
     if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
       LI->setOperand(0, NewV);
       Changed = true;
@@ -1584,7 +1594,10 @@ static bool optimizeOnceStoredGlobal(Glo
   // users of the loaded value (often calls and loads) that would trap if the
   // value was null.
   if (GV->getInitializer()->getType()->isPointerTy() &&
-      GV->getInitializer()->isNullValue()) {
+      GV->getInitializer()->isNullValue() &&
+      !NullPointerIsDefined(
+          nullptr /* F */,
+          GV->getInitializer()->getType()->getPointerAddressSpace())) {
     if (Constant *SOVC = dyn_cast<Constant>(StoredOnceVal)) {
       if (GV->getInitializer()->getType() != SOVC->getType())
         SOVC = ConstantExpr::getBitCast(SOVC, GV->getInitializer()->getType());

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp Mon Jul  9 15:27:23 2018
@@ -4020,7 +4020,9 @@ Instruction *InstCombiner::visitCallSite
     }
   }
 
-  if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
+  if ((isa<ConstantPointerNull>(Callee) &&
+       !NullPointerIsDefined(CS.getInstruction()->getFunction())) ||
+      isa<UndefValue>(Callee)) {
     // If CS does not return void then replaceAllUsesWith undef.
     // This allows ValueHandlers and custom metadata to adjust itself.
     if (!CS.getInstruction()->getType()->isVoidTy())

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp Mon Jul  9 15:27:23 2018
@@ -964,23 +964,26 @@ static Instruction *replaceGEPIdxWithZer
 }
 
 static bool canSimplifyNullStoreOrGEP(StoreInst &SI) {
-  if (SI.getPointerAddressSpace() != 0)
+  if (NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace()))
     return false;
 
   auto *Ptr = SI.getPointerOperand();
   if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(Ptr))
     Ptr = GEPI->getOperand(0);
-  return isa<ConstantPointerNull>(Ptr);
+  return (isa<ConstantPointerNull>(Ptr) &&
+          !NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace()));
 }
 
 static bool canSimplifyNullLoadOrGEP(LoadInst &LI, Value *Op) {
   if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(Op)) {
     const Value *GEPI0 = GEPI->getOperand(0);
-    if (isa<ConstantPointerNull>(GEPI0) && GEPI->getPointerAddressSpace() == 0)
+    if (isa<ConstantPointerNull>(GEPI0) &&
+        !NullPointerIsDefined(LI.getFunction(), GEPI->getPointerAddressSpace()))
       return true;
   }
   if (isa<UndefValue>(Op) ||
-      (isa<ConstantPointerNull>(Op) && LI.getPointerAddressSpace() == 0))
+      (isa<ConstantPointerNull>(Op) &&
+       !NullPointerIsDefined(LI.getFunction(), LI.getPointerAddressSpace())))
     return true;
   return false;
 }
@@ -1076,14 +1079,16 @@ Instruction *InstCombiner::visitLoadInst
 
       // load (select (cond, null, P)) -> load P
       if (isa<ConstantPointerNull>(SI->getOperand(1)) &&
-          LI.getPointerAddressSpace() == 0) {
+          !NullPointerIsDefined(SI->getFunction(),
+                                LI.getPointerAddressSpace())) {
         LI.setOperand(0, SI->getOperand(2));
         return &LI;
       }
 
       // load (select (cond, P, null)) -> load P
       if (isa<ConstantPointerNull>(SI->getOperand(2)) &&
-          LI.getPointerAddressSpace() == 0) {
+          !NullPointerIsDefined(SI->getFunction(),
+                                LI.getPointerAddressSpace())) {
         LI.setOperand(0, SI->getOperand(1));
         return &LI;
       }

Modified: llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp Mon Jul  9 15:27:23 2018
@@ -310,9 +310,13 @@ static Value *getStoredPointerOperand(In
 }
 
 static uint64_t getPointerSize(const Value *V, const DataLayout &DL,
-                               const TargetLibraryInfo &TLI) {
+                               const TargetLibraryInfo &TLI,
+                               const Function *F) {
   uint64_t Size;
-  if (getObjectSize(V, Size, DL, &TLI))
+  ObjectSizeOpts Opts;
+  Opts.NullIsUnknownSize = NullPointerIsDefined(F);
+
+  if (getObjectSize(V, Size, DL, &TLI, Opts))
     return Size;
   return MemoryLocation::UnknownSize;
 }
@@ -343,7 +347,8 @@ static OverwriteResult isOverwrite(const
                                    int64_t &EarlierOff, int64_t &LaterOff,
                                    Instruction *DepWrite,
                                    InstOverlapIntervalsTy &IOL,
-                                   AliasAnalysis &AA) {
+                                   AliasAnalysis &AA,
+                                   const Function *F) {
   // If we don't know the sizes of either access, then we can't do a comparison.
   if (Later.Size == MemoryLocation::UnknownSize ||
       Earlier.Size == MemoryLocation::UnknownSize)
@@ -372,7 +377,7 @@ static OverwriteResult isOverwrite(const
     return OW_Unknown;
 
   // If the "Later" store is to a recognizable object, get its size.
-  uint64_t ObjectSize = getPointerSize(UO2, DL, TLI);
+  uint64_t ObjectSize = getPointerSize(UO2, DL, TLI, F);
   if (ObjectSize != MemoryLocation::UnknownSize)
     if (ObjectSize == Later.Size && ObjectSize >= Earlier.Size)
       return OW_Complete;
@@ -710,7 +715,8 @@ static bool handleFree(CallInst *F, Alia
 static void removeAccessedObjects(const MemoryLocation &LoadedLoc,
                                   SmallSetVector<Value *, 16> &DeadStackObjects,
                                   const DataLayout &DL, AliasAnalysis *AA,
-                                  const TargetLibraryInfo *TLI) {
+                                  const TargetLibraryInfo *TLI,
+                                  const Function *F) {
   const Value *UnderlyingPointer = GetUnderlyingObject(LoadedLoc.Ptr, DL);
 
   // A constant can't be in the dead pointer set.
@@ -727,7 +733,7 @@ static void removeAccessedObjects(const
   // Remove objects that could alias LoadedLoc.
   DeadStackObjects.remove_if([&](Value *I) {
     // See if the loaded location could alias the stack location.
-    MemoryLocation StackLoc(I, getPointerSize(I, DL, *TLI));
+    MemoryLocation StackLoc(I, getPointerSize(I, DL, *TLI, F));
     return !AA->isNoAlias(StackLoc, LoadedLoc);
   });
 }
@@ -841,7 +847,8 @@ static bool handleEndBlock(BasicBlock &B
       // the call is live.
       DeadStackObjects.remove_if([&](Value *I) {
         // See if the call site touches the value.
-        return isRefSet(AA->getModRefInfo(CS, I, getPointerSize(I, DL, *TLI)));
+        return isRefSet(AA->getModRefInfo(CS, I, getPointerSize(I, DL, *TLI,
+                                                                BB.getParent())));
       });
 
       // If all of the allocas were clobbered by the call then we're not going
@@ -880,7 +887,7 @@ static bool handleEndBlock(BasicBlock &B
 
     // Remove any allocas from the DeadPointer set that are loaded, as this
     // makes any stores above the access live.
-    removeAccessedObjects(LoadedLoc, DeadStackObjects, DL, AA, TLI);
+    removeAccessedObjects(LoadedLoc, DeadStackObjects, DL, AA, TLI, BB.getParent());
 
     // If all of the allocas were clobbered by the access then we're not going
     // to find anything else to process.
@@ -1176,7 +1183,8 @@ static bool eliminateDeadStores(BasicBlo
           !isPossibleSelfRead(Inst, Loc, DepWrite, *TLI, *AA)) {
         int64_t InstWriteOffset, DepWriteOffset;
         OverwriteResult OR = isOverwrite(Loc, DepLoc, DL, *TLI, DepWriteOffset,
-                                         InstWriteOffset, DepWrite, IOL, *AA);
+                                         InstWriteOffset, DepWrite, IOL, *AA,
+                                         BB.getParent());
         if (OR == OW_Complete) {
           LLVM_DEBUG(dbgs() << "DSE: Remove Dead Store:\n  DEAD: " << *DepWrite
                             << "\n  KILLER: " << *Inst << '\n');

Modified: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SCCP.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp Mon Jul  9 15:27:23 2018
@@ -1133,8 +1133,12 @@ void SCCPSolver::visitLoadInst(LoadInst
   Constant *Ptr = PtrVal.getConstant();
 
   // load null is undefined.
-  if (isa<ConstantPointerNull>(Ptr) && I.getPointerAddressSpace() == 0)
-    return;
+  if (isa<ConstantPointerNull>(Ptr)) {
+    if (NullPointerIsDefined(I.getFunction(), I.getPointerAddressSpace()))
+      return (void)markOverdefined(IV, &I);
+    else
+      return;
+  }
 
   // Transform load (constant global) into the value loaded.
   if (auto *GV = dyn_cast<GlobalVariable>(Ptr)) {

Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/Local.cpp Mon Jul  9 15:27:23 2018
@@ -2050,7 +2050,9 @@ static bool markAliveBlocks(Function &F,
 
       if (auto *CI = dyn_cast<CallInst>(&I)) {
         Value *Callee = CI->getCalledValue();
-        if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
+        if ((isa<ConstantPointerNull>(Callee) &&
+             !NullPointerIsDefined(CI->getFunction())) ||
+            isa<UndefValue>(Callee)) {
           changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DDT);
           Changed = true;
           break;
@@ -2079,7 +2081,8 @@ static bool markAliveBlocks(Function &F,
 
         if (isa<UndefValue>(Ptr) ||
             (isa<ConstantPointerNull>(Ptr) &&
-             SI->getPointerAddressSpace() == 0)) {
+             !NullPointerIsDefined(SI->getFunction(),
+                                   SI->getPointerAddressSpace()))) {
           changeToUnreachable(SI, true, false, DDT);
           Changed = true;
           break;
@@ -2091,7 +2094,9 @@ static bool markAliveBlocks(Function &F,
     if (auto *II = dyn_cast<InvokeInst>(Terminator)) {
       // Turn invokes that call 'nounwind' functions into ordinary calls.
       Value *Callee = II->getCalledValue();
-      if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
+      if ((isa<ConstantPointerNull>(Callee) &&
+           !NullPointerIsDefined(BB->getParent())) ||
+          isa<UndefValue>(Callee)) {
         changeToUnreachable(II, true, false, DDT);
         Changed = true;
       } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) {

Modified: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp Mon Jul  9 15:27:23 2018
@@ -5950,17 +5950,20 @@ static bool passingValueIsAlwaysUndefine
     // Load from null is undefined.
     if (LoadInst *LI = dyn_cast<LoadInst>(Use))
       if (!LI->isVolatile())
-        return LI->getPointerAddressSpace() == 0;
+        return !NullPointerIsDefined(LI->getFunction(),
+                                     LI->getPointerAddressSpace());
 
     // Store to null is undefined.
     if (StoreInst *SI = dyn_cast<StoreInst>(Use))
       if (!SI->isVolatile())
-        return SI->getPointerAddressSpace() == 0 &&
+        return (!NullPointerIsDefined(SI->getFunction(),
+                                      SI->getPointerAddressSpace())) &&
                SI->getPointerOperand() == I;
 
     // A call to null is undefined.
     if (auto CS = CallSite(Use))
-      return CS.getCalledValue() == I;
+      return !NullPointerIsDefined(CS->getFunction()) &&
+             CS.getCalledValue() == I;
   }
   return false;
 }

Modified: llvm/trunk/test/Analysis/MemorySSA/cyclicphi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/MemorySSA/cyclicphi.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/MemorySSA/cyclicphi.ll (original)
+++ llvm/trunk/test/Analysis/MemorySSA/cyclicphi.ll Mon Jul  9 15:27:23 2018
@@ -33,6 +33,36 @@ bb77:
   br label %bb26
 }
 
+define hidden void @quux_no_null_opt(%struct.hoge *%f) align 2 #0 {
+; CHECK-LABEL: quux_no_null_opt(
+  %tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0
+  %tmp24 = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1
+  %tmp25 = bitcast %struct.widget* %tmp24 to i64**
+  br label %bb26
+
+bb26:                                             ; preds = %bb77, %0
+; CHECK:  3 = MemoryPhi({%0,liveOnEntry},{bb77,2})
+; CHECK-NEXT:   br i1 undef, label %bb68, label %bb77
+  br i1 undef, label %bb68, label %bb77
+
+bb68:                                             ; preds = %bb26
+; CHECK:  MemoryUse(3)
+; CHECK-NEXT:   %tmp69 = load i64, i64* null, align 8
+  %tmp69 = load i64, i64* null, align 8
+; CHECK:  1 = MemoryDef(3)
+; CHECK-NEXT:   store i64 %tmp69, i64* %tmp, align 8
+  store i64 %tmp69, i64* %tmp, align 8
+  br label %bb77
+
+bb77:                                             ; preds = %bb68, %bb26
+; CHECK:  2 = MemoryPhi({bb26,3},{bb68,1})
+; CHECK:  MemoryUse(2)
+; CHECK-NEXT:   %tmp78 = load i64*, i64** %tmp25, align 8
+  %tmp78 = load i64*, i64** %tmp25, align 8
+  %tmp79 = getelementptr inbounds i64, i64* %tmp78, i64 undef
+  br label %bb26
+}
+
 ; CHECK-LABEL: define void @quux_skip
 define void @quux_skip(%struct.hoge* noalias %f, i64* noalias %g) align 2 {
   %tmp = getelementptr inbounds %struct.hoge, %struct.hoge* %f, i64 0, i32 1, i32 0
@@ -121,3 +151,5 @@ bb77:
 ; CHECK-NEXT: br label %bb26
   br label %bb26
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll (original)
+++ llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll Mon Jul  9 15:27:23 2018
@@ -10,6 +10,16 @@ bb:
   ret void
 }
 
+define void @test1_no_null_opt(i8* %ptr) #0 {
+; CHECK: test1_no_null_opt
+  %A = load i8, i8* %ptr
+  br label %bb
+bb:
+  icmp ne i8* %ptr, null
+; CHECK: icmp ne i8* %ptr, null
+  ret void
+}
+
 define void @test2(i8* %ptr) {
 ; CHECK: test2
   store i8 0, i8* %ptr
@@ -20,6 +30,16 @@ bb:
   ret void
 }
 
+define void @test2_no_null_opt(i8* %ptr) #0 {
+; CHECK: test2_no_null_opt
+  store i8 0, i8* %ptr
+  br label %bb
+bb:
+  icmp ne i8* %ptr, null
+; CHECK: icmp ne i8* %ptr, null
+  ret void
+}
+
 define void @test3() {
 ; CHECK: test3
   %ptr = alloca i8
@@ -30,6 +50,17 @@ bb:
   ret void
 }
 
+;; OK to remove icmp here since ptr is coming from alloca.
+define void @test3_no_null_opt() #0 {
+; CHECK: test3
+  %ptr = alloca i8
+  br label %bb
+bb:
+  icmp ne i8* %ptr, null
+; CHECK-NOT: icmp
+  ret void
+}
+
 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
 define void @test4(i8* %dest, i8* %src) {
 ; CHECK: test4
@@ -42,6 +73,18 @@ bb:
   ret void
 }
 
+define void @test4_no_null_opt(i8* %dest, i8* %src) #0 {
+; CHECK: test4_no_null_opt
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 false)
+  br label %bb
+bb:
+  icmp ne i8* %dest, null
+  icmp ne i8* %src, null
+; CHECK: icmp ne i8* %dest, null
+; CHECK: icmp ne i8* %src, null
+  ret void
+}
+
 declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i1)
 define void @test5(i8* %dest, i8* %src) {
 ; CHECK: test5
@@ -54,6 +97,18 @@ bb:
   ret void
 }
 
+define void @test5_no_null_opt(i8* %dest, i8* %src) #0 {
+; CHECK: test5_no_null_opt
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 false)
+  br label %bb
+bb:
+  icmp ne i8* %dest, null
+  icmp ne i8* %src, null
+; CHECK: icmp ne i8* %dest, null
+; CHECK: icmp ne i8* %src, null
+  ret void
+}
+
 declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i1)
 define void @test6(i8* %dest) {
 ; CHECK: test6
@@ -65,6 +120,16 @@ bb:
   ret void
 }
 
+define void @test6_no_null_opt(i8* %dest) #0 {
+; CHECK: test6_no_null_opt
+  call void @llvm.memset.p0i8.i32(i8* %dest, i8 255, i32 1, i1 false)
+  br label %bb
+bb:
+  icmp ne i8* %dest, null
+; CHECK: icmp ne i8* %dest, null
+  ret void
+}
+
 define void @test7(i8* %dest, i8* %src, i32 %len) {
 ; CHECK: test7
   call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
@@ -161,3 +226,5 @@ merge:
   ; CHECK: call void @test12_helper(i8* nonnull %merged_arg)
   ret void
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll Mon Jul  9 15:27:23 2018
@@ -224,8 +224,17 @@ define i32* @gep1(i32* %p) {
   ret i32* %q
 }
 
+define i32* @gep1_no_null_opt(i32* %p) #0 {
+; Should't be able to derive nonnull based on gep.
+; CHECK: define i32* @gep1_no_null_opt(
+  %q = getelementptr inbounds i32, i32* %p, i32 1
+  ret i32* %q
+}
+
 ; CHECK: define i32 addrspace(3)* @gep2(
 define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) {
   %q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1
   ret i32 addrspace(3)* %q
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GVN/PRE/2018-06-08-pre-load-dbgloc-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GVN/PRE/2018-06-08-pre-load-dbgloc-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GVN/PRE/2018-06-08-pre-load-dbgloc-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GVN/PRE/2018-06-08-pre-load-dbgloc-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,82 @@
+; This test checks if debug loc is propagated to load/store created by GVN/Instcombine.
+; RUN: opt < %s -gvn -S | FileCheck %s --check-prefixes=ALL
+; RUN: opt < %s -gvn -instcombine -S | FileCheck %s --check-prefixes=ALL
+
+; struct node {
+;  int  *v;
+; struct desc *descs;
+; };
+
+; struct desc {
+;  struct node *node;
+; };
+
+; extern int bar(void *v, void* n);
+
+; int test(struct desc *desc)
+; {
+;  void *v, *n;
+;  v = !desc ? ((void *)0) : desc->node->v;  // Line 15
+;  n = &desc->node->descs[0];                // Line 16
+;  return bar(v, n);
+; }
+
+; Line 16, Column 13:
+;   n = &desc->node->descs[0];
+;              ^
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-gnu"
+
+%struct.desc = type { %struct.node* }
+%struct.node = type { i32*, %struct.desc* }
+
+define i32 @test_no_null_opt(%struct.desc* readonly %desc) local_unnamed_addr #0 !dbg !4 {
+entry:
+  %tobool = icmp eq %struct.desc* %desc, null
+  br i1 %tobool, label %cond.end, label %cond.false, !dbg !9
+; ALL: br i1 %tobool, label %entry.cond.end_crit_edge, label %cond.false, !dbg [[LOC_15_6:![0-9]+]]
+; ALL: entry.cond.end_crit_edge:
+; ALL: load %struct.node*, %struct.node** null, align {{[0-9]+}}, !dbg [[LOC_16_13:![0-9]+]]
+
+cond.false:
+  %0 = bitcast %struct.desc* %desc to i8***, !dbg !11
+  %1 = load i8**, i8*** %0, align 8, !dbg !11
+  %2 = load i8*, i8** %1, align 8
+  br label %cond.end, !dbg !9
+
+cond.end:
+; ALL: phi %struct.node* [ %3, %cond.false ], [ %.pre, %entry.cond.end_crit_edge ]
+; ALL: phi i8* [ %2, %cond.false ], [ null, %entry.cond.end_crit_edge ]
+
+  %3 = phi i8* [ %2, %cond.false ], [ null, %entry ], !dbg !9
+  %node2 = getelementptr inbounds %struct.desc, %struct.desc* %desc, i64 0, i32 0
+  %4 = load %struct.node*, %struct.node** %node2, align 8, !dbg !10
+  %descs = getelementptr inbounds %struct.node, %struct.node* %4, i64 0, i32 1
+  %5 = bitcast %struct.desc** %descs to i8**
+  %6 = load i8*, i8** %5, align 8
+  %call = tail call i32 @bar(i8* %3, i8* %6)
+  ret i32 %call
+}
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+declare i32 @bar(i8*, i8*) local_unnamed_addr #1
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug)
+!1 = !DIFile(filename: "test.c", directory: ".")
+!2 = !{i32 2, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = distinct !DISubprogram(name: "test_no_null_opt", scope: !1, file: !1, line: 12, type: !5, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !8)
+!5 = !DISubroutineType(types: !6)
+!6 = !{!7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{}
+!9 = !DILocation(line: 15, column: 6, scope: !4)
+!10 = !DILocation(line: 16, column: 13, scope: !4)
+!11 = !DILocation(line: 15, column: 34, scope: !4)
+
+;ALL: [[SCOPE:![0-9]+]] = distinct  !DISubprogram(name: "test_no_null_opt",{{.*}}
+;ALL: [[LOC_15_6]] = !DILocation(line: 15, column: 6, scope: [[SCOPE]])
+;ALL: [[LOC_16_13]] = !DILocation(line: 16, column: 13, scope: [[SCOPE]])

Added: llvm/trunk/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,34 @@
+; RUN: opt -globalopt -S < %s | FileCheck %s
+; CHECK: @Y
+; CHECK: section ".foo"
+
+%struct.xyz = type { double, i32 }
+
+ at Y = internal global %struct.xyz* null ,section ".foo"            ; <%struct.xyz**> [#uses=2]
+ at numf2s = external global i32                     ; <i32*> [#uses=1]
+
+define void @init_net() #0 {
+; CHECK-LABEL: init_net(
+; CHECK: load i32, i32* @numf2s
+; CHECK: call i8* @malloc
+; CHECK: store %struct.xyz* {{.*}}, %struct.xyz** @Y
+entry:
+  %0 = load i32, i32* @numf2s, align 4                 ; <i32> [#uses=1]
+  %mallocsize2 = shl i32 %0, 4                    ; <i32> [#uses=1]
+  %malloccall3 = tail call i8* @malloc(i32 %mallocsize2)  ; <i8*> [#uses=1]
+  %1 = bitcast i8* %malloccall3 to %struct.xyz*   ; <%struct.xyz*> [#uses=1]
+  store %struct.xyz* %1, %struct.xyz** @Y, align 8
+  ret void
+}
+
+define %struct.xyz* @load_train() #0 {
+; CHECK-LABEL: load_train(
+; CHECK: load %struct.xyz*, %struct.xyz** @Y
+entry:
+  %0 = load %struct.xyz*, %struct.xyz** @Y, align 8             ; <%struct.xyz*> [#uses=0]
+  ret %struct.xyz* %0
+}
+
+declare noalias i8* @malloc(i32)
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,40 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+%struct.foo = type { i32, i32 }
+ at X = internal global %struct.foo* null
+; CHECK: @X
+; CHECK-NOT: @X.f0
+
+define void @bar(i64 %Size) nounwind noinline #0 {
+entry:
+  %mallocsize = mul i64 %Size, 8                  ; <i64> [#uses=1]
+  %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1]
+  %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1]
+	store %struct.foo* %.sub, %struct.foo** @X, align 4
+	ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+define i32 @baz() nounwind readonly noinline #0 {
+bb1.thread:
+	%0 = load %struct.foo*, %struct.foo** @X, align 4
+	br label %bb1
+
+bb1:		; preds = %bb1, %bb1.thread
+	%i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ]
+	%sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ]
+	%1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0
+	%2 = load i32, i32* %1, align 4
+	%3 = add i32 %2, %sum.0.reg2mem.0
+	%indvar.next = add i32 %i.0.reg2mem.0, 1
+	%exitcond = icmp eq i32 %indvar.next, 1200
+	br i1 %exitcond, label %bb2, label %bb1
+
+bb2:		; preds = %bb1
+	ret i32 %3
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+

Modified: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-1.ll Mon Jul  9 15:27:23 2018
@@ -36,3 +36,10 @@ bb2:		; preds = %bb1
 	ret i32 %3
 }
 
+define void @bam(i64 %Size) nounwind noinline #0 {
+entry:
+	%0 = load %struct.foo*, %struct.foo** @X, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,39 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+%struct.foo = type { i32, i32 }
+ at X = internal global %struct.foo* null		; <%struct.foo**> [#uses=2]
+; CHECK: @X
+; CHECK-NOT: @X.f0
+
+define void @bar(i32 %Size) nounwind noinline #0 {
+entry:
+	%malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1]
+	%0 = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1]
+	%.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %0, i32 0, i32 0		; <%struct.foo*> [#uses=1]
+	store %struct.foo* %.sub, %struct.foo** @X, align 4
+	ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+define i32 @baz() nounwind readonly noinline #0 {
+bb1.thread:
+	%0 = load %struct.foo*, %struct.foo** @X, align 4		; <%struct.foo*> [#uses=1]
+	br label %bb1
+
+bb1:		; preds = %bb1, %bb1.thread
+	%i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ]		; <i32> [#uses=2]
+	%sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ]		; <i32> [#uses=1]
+	%1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0		; <i32*> [#uses=1]
+	%2 = load i32, i32* %1, align 4		; <i32> [#uses=1]
+	%3 = add i32 %2, %sum.0.reg2mem.0		; <i32> [#uses=2]
+	%indvar.next = add i32 %i.0.reg2mem.0, 1		; <i32> [#uses=2]
+	%exitcond = icmp eq i32 %indvar.next, 1200		; <i1> [#uses=1]
+	br i1 %exitcond, label %bb2, label %bb1
+
+bb2:		; preds = %bb1
+	ret i32 %3
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-2.ll Mon Jul  9 15:27:23 2018
@@ -36,3 +36,10 @@ bb2:		; preds = %bb1
 	ret i32 %3
 }
 
+define void @bam(i64 %Size) nounwind noinline #0 {
+entry:
+        %0 = load %struct.foo*, %struct.foo** @X, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,41 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+%struct.foo = type { i32, i32 }
+ at X = internal global %struct.foo* null
+; CHECK: @X
+; CHECK-NOT: @X.f0
+
+define void @bar(i64 %Size) nounwind noinline #0 {
+entry:
+  %mallocsize = mul i64 8, %Size ; <i64> [#uses=1]
+; CHECK: mul i64 8, %Size
+  %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1]
+  %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1]
+	store %struct.foo* %.sub, %struct.foo** @X, align 4
+	ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+define i32 @baz() nounwind readonly noinline #0 {
+bb1.thread:
+; CHECK: load %struct.foo*, %struct.foo** @X, align 4
+	%0 = load %struct.foo*, %struct.foo** @X, align 4
+	br label %bb1
+
+bb1:		; preds = %bb1, %bb1.thread
+	%i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ]
+	%sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ]
+	%1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0
+	%2 = load i32, i32* %1, align 4
+	%3 = add i32 %2, %sum.0.reg2mem.0
+	%indvar.next = add i32 %i.0.reg2mem.0, 1
+	%exitcond = icmp eq i32 %indvar.next, 1200
+	br i1 %exitcond, label %bb2, label %bb1
+
+bb2:		; preds = %bb1
+	ret i32 %3
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-3.ll Mon Jul  9 15:27:23 2018
@@ -37,3 +37,10 @@ bb2:		; preds = %bb1
 	ret i32 %3
 }
 
+define void @bam(i64 %Size) nounwind noinline #0 {
+entry:
+        %0 = load %struct.foo*, %struct.foo** @X, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,44 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+%struct.foo = type { i32, i32 }
+
+ at X = internal global %struct.foo* null
+; CHECK: @X
+; CHECK-NOT: @X.f0
+
+define void @bar(i64 %Size) nounwind noinline #0 {
+entry:
+  %mallocsize = shl i64 %Size, 3                  ; <i64> [#uses=1]
+  %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1]
+; CHECK: shl i64 %Size, 3
+  %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1]
+	store %struct.foo* %.sub, %struct.foo** @X, align 4
+	ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+define i32 @baz() nounwind readonly noinline #0 {
+; CHECK-LABEL: @baz(
+bb1.thread:
+; CHECK: load %struct.foo*, %struct.foo** @X, align 4
+	%0 = load %struct.foo*, %struct.foo** @X, align 4
+	br label %bb1
+
+bb1:		; preds = %bb1, %bb1.thread
+	%i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ]
+	%sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ]
+	%1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0
+	%2 = load i32, i32* %1, align 4
+; CHECK: load i32, i32* %1, align 4
+	%3 = add i32 %2, %sum.0.reg2mem.0
+	%indvar.next = add i32 %i.0.reg2mem.0, 1
+	%exitcond = icmp eq i32 %indvar.next, 1200
+	br i1 %exitcond, label %bb2, label %bb1
+
+bb2:		; preds = %bb1
+	ret i32 %3
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-4.ll Mon Jul  9 15:27:23 2018
@@ -37,3 +37,11 @@ bb2:		; preds = %bb1
 	ret i32 %3
 }
 
+define void @bam(i64 %Size) nounwind noinline #0 {
+entry:
+        %0 = load %struct.foo*, %struct.foo** @X, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+

Added: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,54 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+%struct.foo = type { i32, i32 }
+
+ at X = internal global %struct.foo* null		; <%struct.foo**> [#uses=2]
+; CHECK: @X
+; CHECK-NOT: @X.f0
+
+define void @bar(i32 %Size) nounwind noinline #0 {
+;  CHECK-LABEL: @bar(
+entry:
+	%malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1]
+	%tmp = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1]
+	%.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %tmp, i32 0, i32 0		; <%struct.foo*> [#uses=1]
+	store %struct.foo* %.sub, %struct.foo** @X, align 4
+	ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+define i32 @baz() nounwind readonly noinline #0 {
+; CHECK-LABEL: @baz(
+bb1.thread:
+	%tmpLD1 = load %struct.foo*, %struct.foo** @X, align 4		; <%struct.foo*> [#uses=1]
+; CHECK: load %struct.foo*, %struct.foo** @X, align 4
+	br label %bb1
+
+bb1:		; preds = %bb1, %bb1.thread
+        %tmp = phi %struct.foo* [%tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ]		; <i32> [#uses=2]
+; CHECK: %tmp = phi %struct.foo* [ %tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ]
+	%i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ]		; <i32> [#uses=2]
+	%sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %tmp3, %bb1 ]		; <i32> [#uses=1]
+	%tmp1 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 0		; <i32*> [#uses=1]
+	%tmp2 = load i32, i32* %tmp1, align 4		; <i32> [#uses=1]
+; CHECK: load i32, i32* %tmp1, align 4
+	%tmp6 = add i32 %tmp2, %sum.0.reg2mem.0		; <i32> [#uses=2]
+	%tmp4 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 1		; <i32*> [#uses=1]
+        %tmp5 = load i32 , i32 * %tmp4
+;  CHECK: load i32, i32* %tmp4
+        %tmp3 = add i32 %tmp5, %tmp6
+	%indvar.next = add i32 %i.0.reg2mem.0, 1		; <i32> [#uses=2]
+
+      	%tmpLD2 = load %struct.foo*, %struct.foo** @X, align 4		; <%struct.foo*> [#uses=1]
+; CHECK: load %struct.foo*, %struct.foo** @X, align 4
+
+	%exitcond = icmp eq i32 %indvar.next, 1200		; <i1> [#uses=1]
+	br i1 %exitcond, label %bb2, label %bb1
+
+bb2:		; preds = %bb1
+	ret i32 %tmp3
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/heap-sra-phi.ll Mon Jul  9 15:27:23 2018
@@ -42,3 +42,11 @@ bb1:		; preds = %bb1, %bb1.thread
 bb2:		; preds = %bb1
 	ret i32 %tmp3
 }
+
+define void @bam(i64 %Size) nounwind noinline #0 {
+entry:
+        %0 = load %struct.foo*, %struct.foo** @X, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,28 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+ at a = internal global i64* null, align 8
+; CHECK: @a
+
+; PR13968
+define void @qux_no_null_opt() nounwind #0 {
+; CHECK-LABEL: @qux_no_null_opt(
+; CHECK: getelementptr i64*, i64** @a, i32 1
+; CHECK: store i64* inttoptr (i64 1 to i64*), i64** @a
+  %b = bitcast i64** @a to i8*
+  %g = getelementptr i64*, i64** @a, i32 1
+  %cmp = icmp ne i8* null, %b
+  %cmp2 = icmp eq i8* null, %b
+  %cmp3 = icmp eq i64** null, %g
+  store i64* inttoptr (i64 1 to i64*), i64** @a, align 8
+  %l = load i64*, i64** @a, align 8
+  ret void
+}
+
+define i64* @bar() {
+  %X = load i64*, i64** @a, align 8
+  ret i64* %X
+; CHECK-LABEL: @bar(
+; CHECK: load
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,31 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+ at G = internal global i32* null          ; <i32**> [#uses=3]
+; CHECK: global
+
+define void @init() #0 {
+; CHECK-LABEL: @init(
+; CHECK: store
+; CHECK: load
+        %malloccall = tail call i8* @malloc(i64 4)      ; <i8*> [#uses=1]
+        %P = bitcast i8* %malloccall to i32*            ; <i32*> [#uses=1]
+        store i32* %P, i32** @G
+        %GV = load i32*, i32** @G             ; <i32*> [#uses=1]
+        store i32 0, i32* %GV
+        ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+define i32 @get() #0 {
+; CHECK-LABEL: @get(
+; CHECK: load i32*, i32** @G
+; CHECK-NEXT: load i32, i32* %GV
+        %GV = load i32*, i32** @G             ; <i32*> [#uses=1]
+        %V = load i32, i32* %GV              ; <i32> [#uses=1]
+        ret i32 %V
+; CHECK: ret i32 %V
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-1.ll Mon Jul  9 15:27:23 2018
@@ -1,7 +1,7 @@
 ; RUN: opt < %s -globalopt -S | FileCheck %s
 target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
 
- at G = internal global i32* null          ; <i32**> [#uses=3]
+ at G = internal global i32* null          ; <i32**> [#uses=4]
 ; CHECK-NOT: global
 
 define void @init() {
@@ -22,3 +22,11 @@ define i32 @get() {
 ; CHECK: ret i32 0
 }
 
+define void @foo(i64 %Size) nounwind noinline #0 {
+entry:
+        %0 = load i32*, i32** @G, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+

Added: llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,24 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+
+ at G = internal global i32* null
+
+define void @t() #0 {
+; CHECK: @t()
+; CHECK: call i8* @malloc
+; CHECK: bitcast
+; CHECK: store
+; CHECK: load
+; CHECK: getelementptr
+; CHECK: store
+  %malloccall = tail call i8* @malloc(i64 mul (i64 100, i64 4))
+  %P = bitcast i8* %malloccall to i32*
+  store i32* %P, i32** @G
+  %GV = load i32*, i32** @G
+  %GVe = getelementptr i32, i32* %GV, i32 40
+  store i32 20, i32* %GVe
+  ret void
+}
+
+declare noalias i8* @malloc(i64)
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2.ll (original)
+++ llvm/trunk/test/Transforms/GlobalOpt/malloc-promote-2.ll Mon Jul  9 15:27:23 2018
@@ -17,3 +17,11 @@ define void @t() {
 }
 
 declare noalias i8* @malloc(i64)
+
+define void @foo(i64 %Size) nounwind noinline #0 {
+entry:
+        %0 = load i32*, i32** @G, align 4
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,40 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+; CHECK: global
+
+ at G = internal global void ()* null              ; <void ()**> [#uses=2]
+
+define internal void @Actual() {
+; CHECK-LABEL: Actual(
+        ret void
+}
+
+define void @init() {
+; CHECK-LABEL: init(
+; CHECK: store void ()* @Actual, void ()** @G
+        store void ()* @Actual, void ()** @G
+        ret void
+}
+
+define void @doit() #0 {
+; CHECK-LABEL: doit(
+        %FP = load void ()*, void ()** @G         ; <void ()*> [#uses=2]
+; CHECK: %FP = load void ()*, void ()** @G
+        %CC = icmp eq void ()* %FP, null                ; <i1> [#uses=1]
+; CHECK: %CC = icmp eq void ()* %FP, null
+        br i1 %CC, label %isNull, label %DoCall
+; CHECK: br i1 %CC, label %isNull, label %DoCall
+
+DoCall:         ; preds = %0
+; CHECK: DoCall:
+; CHECK: call void %FP()
+; CHECK: ret void
+        call void %FP( )
+        ret void
+
+isNull:         ; preds = %0
+; CHECK: isNull:
+; CHECK: ret void
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,27 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+ at G = internal global void ()* null              ; <void ()**> [#uses=2]
+; CHECK: global
+
+define internal void @Actual() {
+; CHECK-LABEL: Actual(
+        ret void
+}
+
+define void @init() {
+; CHECK-LABEL: init(
+; CHECK:  store void ()* @Actual, void ()** @G
+        store void ()* @Actual, void ()** @G
+        ret void
+}
+
+define void @doit() #0 {
+; CHECK-LABEL: doit(
+; CHECK: %FP = load void ()*, void ()** @G
+; CHECK: call void %FP()
+        %FP = load void ()*, void ()** @G         ; <void ()*> [#uses=1]
+        call void %FP( )
+        ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/IPConstantProp/PR26044.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IPConstantProp/PR26044.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/IPConstantProp/PR26044.ll (original)
+++ llvm/trunk/test/Transforms/IPConstantProp/PR26044.ll Mon Jul  9 15:27:23 2018
@@ -23,9 +23,40 @@ entry:
   ret i32 %cond
 }
 
+define void @fn_no_null_opt() #0 {
+entry:
+  br label %if.end
+
+for.cond1:                                        ; preds = %if.end, %for.end
+  br i1 undef, label %if.end, label %if.end
+
+if.end:                                           ; preds = %lbl, %for.cond1
+  %e.2 = phi i32* [ undef, %entry ], [ null, %for.cond1 ], [ null, %for.cond1 ]
+  %0 = load i32, i32* %e.2, align 4
+  %call = call i32 @fn0(i32 %0)
+  br label %for.cond1
+}
+
+define internal i32 @fn0(i32 %p1) {
+entry:
+  %tobool = icmp ne i32 %p1, 0
+  %cond = select i1 %tobool, i32 %p1, i32 %p1
+  ret i32 %cond
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
 ; CHECK-LABEL: define void @fn2(
 ; CHECK: call i32 @fn1(i32 undef)
 
 ; CHECK-LABEL: define internal i32 @fn1(
 ; CHECK:%[[COND:.*]] = select i1 undef, i32 undef, i32 undef
 ; CHECK: ret i32 %[[COND]]
+
+; CHECK-LABEL: define void @fn_no_null_opt(
+; CHECK: call i32 @fn0(i32 %0)
+
+; CHECK-LABEL: define internal i32 @fn0(
+; CHECK:%[[TOBOOL:.*]] = icmp ne i32 %p1, 0
+; CHECK:%[[COND:.*]] = select i1 %[[TOBOOL]], i32 %p1, i32 %p1
+; CHECK: ret i32 %[[COND]]

Modified: llvm/trunk/test/Transforms/Inline/attributes.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/attributes.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/Inline/attributes.ll (original)
+++ llvm/trunk/test/Transforms/Inline/attributes.ll Mon Jul  9 15:27:23 2018
@@ -333,6 +333,50 @@ define i32 @test_no-use-jump-tables3(i32
 ; CHECK-NEXT: ret i32
 }
 
+; Calle with "null-pointer-is-valid"="true" attribute should not be inlined
+; into a caller without this attribute. Exception: alwaysinline callee
+; can still be inlined.
+
+define i32 @null-pointer-is-valid_callee0(i32 %i) "null-pointer-is-valid"="true" {
+  ret i32 %i
+; CHECK: @null-pointer-is-valid_callee0(i32 %i)
+; CHECK-NEXT: ret i32
+}
+
+define i32 @null-pointer-is-valid_callee1(i32 %i) alwaysinline "null-pointer-is-valid"="true" {
+  ret i32 %i
+; CHECK: @null-pointer-is-valid_callee1(i32 %i)
+; CHECK-NEXT: ret i32
+}
+
+define i32 @null-pointer-is-valid_callee2(i32 %i)  {
+  ret i32 %i
+; CHECK: @null-pointer-is-valid_callee2(i32 %i)
+; CHECK-NEXT: ret i32
+}
+
+define i32 @test_null-pointer-is-valid0(i32 %i) {
+  %1 = call i32 @null-pointer-is-valid_callee0(i32 %i)
+  ret i32 %1
+; CHECK: @test_null-pointer-is-valid0(
+; CHECK: call i32 @null-pointer-is-valid_callee0
+; CHECK-NEXT: ret i32
+}
+
+define i32 @test_null-pointer-is-valid1(i32 %i) {
+  %1 = call i32 @null-pointer-is-valid_callee1(i32 %i)
+  ret i32 %1
+; CHECK: @test_null-pointer-is-valid1(
+; CHECK-NEXT: ret i32
+}
+
+define i32 @test_null-pointer-is-valid2(i32 %i) "null-pointer-is-valid"="true" {
+  %1 = call i32 @null-pointer-is-valid_callee2(i32 %i)
+  ret i32 %1
+; CHECK: @test_null-pointer-is-valid2(
+; CHECK-NEXT: ret i32
+}
+
 ; CHECK: attributes [[FPMAD_FALSE]] = { "less-precise-fpmad"="false" }
 ; CHECK: attributes [[FPMAD_TRUE]] = { "less-precise-fpmad"="true" }
 ; CHECK: attributes [[NOIMPLICITFLOAT]] = { noimplicitfloat }

Modified: llvm/trunk/test/Transforms/InstCombine/atomic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/atomic.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/atomic.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/atomic.ll Mon Jul  9 15:27:23 2018
@@ -102,6 +102,13 @@ define i32 @test9() {
   ret i32 %x
 }
 
+define i32 @test9_no_null_opt() #0 {
+; CHECK-LABEL: define i32 @test9_no_null_opt(
+; CHECK: load atomic i32, i32* null unordered
+  %x = load atomic i32, i32* null unordered, align 4
+  ret i32 %x
+}
+
 ; FIXME: Could also fold
 define i32 @test10() {
 ; CHECK-LABEL: define i32 @test10(
@@ -110,6 +117,13 @@ define i32 @test10() {
   ret i32 %x
 }
 
+define i32 @test10_no_null_opt() #0 {
+; CHECK-LABEL: define i32 @test10_no_null_opt(
+; CHECK: load atomic i32, i32* null monotonic
+  %x = load atomic i32, i32* null monotonic, align 4
+  ret i32 %x
+}
+
 ; Would this be legal to fold?  Probably?
 define i32 @test11() {
 ; CHECK-LABEL: define i32 @test11(
@@ -118,6 +132,13 @@ define i32 @test11() {
   ret i32 %x
 }
 
+define i32 @test11_no_null_opt() #0 {
+; CHECK-LABEL: define i32 @test11_no_null_opt(
+; CHECK: load atomic i32, i32* null seq_cst
+  %x = load atomic i32, i32* null seq_cst, align 4
+  ret i32 %x
+}
+
 ; An unordered access to null is still unreachable.  There's no
 ; ordering imposed.
 define i32 @test12() {
@@ -127,6 +148,13 @@ define i32 @test12() {
   ret i32 0
 }
 
+define i32 @test12_no_null_opt() #0 {
+; CHECK-LABEL: define i32 @test12_no_null_opt(
+; CHECK: store atomic i32 0, i32* null unordered
+  store atomic i32 0, i32* null unordered, align 4
+  ret i32 0
+}
+
 ; FIXME: Could also fold
 define i32 @test13() {
 ; CHECK-LABEL: define i32 @test13(
@@ -135,6 +163,13 @@ define i32 @test13() {
   ret i32 0
 }
 
+define i32 @test13_no_null_opt() #0 {
+; CHECK-LABEL: define i32 @test13_no_null_opt(
+; CHECK: store atomic i32 0, i32* null monotonic
+  store atomic i32 0, i32* null monotonic, align 4
+  ret i32 0
+}
+
 ; Would this be legal to fold?  Probably?
 define i32 @test14() {
 ; CHECK-LABEL: define i32 @test14(
@@ -143,6 +178,13 @@ define i32 @test14() {
   ret i32 0
 }
 
+define i32 @test14_no_null_opt() #0 {
+; CHECK-LABEL: define i32 @test14_no_null_opt(
+; CHECK: store atomic i32 0, i32* null seq_cst
+  store atomic i32 0, i32* null seq_cst, align 4
+  ret i32 0
+}
+
 @a = external global i32
 @b = external global i32
 
@@ -287,3 +329,5 @@ define void @no_atomic_vector_store(<2 x
   store atomic i64 %1, i64* %2 unordered, align 8
   ret void
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstCombine/invariant.group.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invariant.group.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invariant.group.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/invariant.group.ll Mon Jul  9 15:27:23 2018
@@ -8,6 +8,13 @@ define i8* @simplifyNullLaunder() {
   ret i8* %b2
 }
 
+; CHECK-LABEL: define i8* @dontSimplifyNullLaunderNoNullOpt()
+define i8* @dontSimplifyNullLaunderNoNullOpt() #0 {
+; CHECK-NEXT: call i8* @llvm.launder.invariant.group.p0i8(i8* null)
+  %b2 = call i8* @llvm.launder.invariant.group.p0i8(i8* null)
+  ret i8* %b2
+}
+
 ; CHECK-LABEL: define i8 addrspace(42)* @dontsimplifyNullLaunderForDifferentAddrspace()
 define i8 addrspace(42)* @dontsimplifyNullLaunderForDifferentAddrspace() {
 ; CHECK: %b2 = call i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)* null)
@@ -41,6 +48,13 @@ define i8* @simplifyNullStrip() {
   ret i8* %b2
 }
 
+; CHECK-LABEL: define i8* @dontSimplifyNullStripNonNullOpt()
+define i8* @dontSimplifyNullStripNonNullOpt() #0 {
+; CHECK-NEXT: call i8* @llvm.strip.invariant.group.p0i8(i8* null)
+  %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* null)
+  ret i8* %b2
+}
+
 ; CHECK-LABEL: define i8 addrspace(42)* @dontsimplifyNullStripForDifferentAddrspace()
 define i8 addrspace(42)* @dontsimplifyNullStripForDifferentAddrspace() {
 ; CHECK: %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* null)
@@ -66,3 +80,4 @@ define i8 addrspace(42)* @simplifyUndefS
 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
 declare i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)*)
 
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstCombine/invoke.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/invoke.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/invoke.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/invoke.ll Mon Jul  9 15:27:23 2018
@@ -47,6 +47,27 @@ lpad:
   unreachable
 }
 
+; CHECK-LABEL: @f2_no_null_opt(
+define i64 @f2_no_null_opt() nounwind uwtable ssp #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+; CHECK: invoke noalias i8* null()
+  %call = invoke noalias i8* null()
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+; CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %call, i1 false, i1 false)
+  %0 = tail call i64 @llvm.objectsize.i64(i8* %call, i1 false)
+  ret i64 %0
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %2 = extractvalue { i8*, i32 } %1, 0
+  tail call void @__cxa_call_unexpected(i8* %2) noreturn nounwind
+  unreachable
+}
+attributes #0 = { "null-pointer-is-valid"="true" }
+
 ; CHECK-LABEL: @f3(
 define void @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
 ; CHECK: invoke void @llvm.donothing()

Added: llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/lifetime-no-null-opt.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,94 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @foo(i8* nocapture, i8* nocapture)
+
+define void @bar(i1 %flag) #0 !dbg !4 {
+entry:
+; CHECK-LABEL: @bar(
+; CHECK: %[[T:[^ ]+]] = getelementptr inbounds [1 x i8], [1 x i8]* %text
+; CHECK: %[[B:[^ ]+]] = getelementptr inbounds [1 x i8], [1 x i8]* %buff
+; CHECK: if:
+; CHECK-NEXT: br label %bb2
+; CHECK: bb2:
+; CHECK-NEXT: br label %bb3
+; CHECK: bb3:
+; CHECK-NEXT: call void @llvm.dbg.declare
+; CHECK-NEXT: br label %fin
+; CHECK: call void @llvm.lifetime.start.p0i8(i64 1, i8* %[[T]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* %[[B]])
+; CHECK-NEXT: call void @foo(i8* %[[B]], i8* %[[T]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[B]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* %[[T]])
+  %text = alloca [1 x i8], align 1
+  %buff = alloca [1 x i8], align 1
+  %0 = getelementptr inbounds [1 x i8], [1 x i8]* %text, i64 0, i64 0
+  %1 = getelementptr inbounds [1 x i8], [1 x i8]* %buff, i64 0, i64 0
+  br i1 %flag, label %if, label %else
+
+if:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br label %bb2
+
+bb2:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  br label %bb3
+
+bb3:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.dbg.declare(metadata [1 x i8]* %text, metadata !14, metadata !25), !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br label %fin
+
+else:
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* %1)
+  call void @foo(i8* %1, i8* %0)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %1)
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* %0)
+  br  label %fin
+
+fin:
+  ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!22, !23}
+!llvm.ident = !{!24}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 248826) (llvm/trunk 248827)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "test.cpp", directory: "/home/user")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "bar", linkageName: "bar", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !8)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7}
+!7 = !DIBasicType(name: "bool", size: 8, align: 8, encoding: DW_ATE_boolean)
+!8 = !{!9, !11, !12, !14, !21}
+!9 = !DILocalVariable(name: "Size", arg: 1, scope: !4, file: !1, line: 2, type: !10)
+!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!11 = !DILocalVariable(name: "flag", arg: 2, scope: !4, file: !1, line: 2, type: !7)
+!12 = !DILocalVariable(name: "i", scope: !13, file: !1, line: 3, type: !10)
+!13 = distinct !DILexicalBlock(scope: !4, file: !1, line: 3, column: 3)
+!14 = !DILocalVariable(name: "text", scope: !15, file: !1, line: 4, type: !17)
+!15 = distinct !DILexicalBlock(scope: !16, file: !1, line: 3, column: 30)
+!16 = distinct !DILexicalBlock(scope: !13, file: !1, line: 3, column: 3)
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 8, align: 8, elements: !19)
+!18 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+!19 = !{!20}
+!20 = !DISubrange(count: 1)
+!21 = !DILocalVariable(name: "buff", scope: !15, file: !1, line: 5, type: !17)
+!22 = !{i32 2, !"Dwarf Version", i32 4}
+!23 = !{i32 2, !"Debug Info Version", i32 3}
+!24 = !{!"clang version 3.8.0 (trunk 248826) (llvm/trunk 248827)"}
+!25 = !DIExpression()
+!26 = !DILocation(line: 4, column: 10, scope: !15)

Modified: llvm/trunk/test/Transforms/InstCombine/load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/load.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/load.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/load.ll Mon Jul  9 15:27:23 2018
@@ -60,6 +60,16 @@ define i32 @test7(i32 %X) {
 	ret i32 %R
 }
 
+; CHECK-LABEL: @test7_no_null_opt(
+; CHECK: %V = getelementptr i32, i32* null
+; CHECK: %R = load i32, i32* %V
+define i32 @test7_no_null_opt(i32 %X) #0 {
+        %V = getelementptr i32, i32* null, i32 %X               ; <i32*> [#uses=1]
+        %R = load i32, i32* %V          ; <i32> [#uses=1]
+        ret i32 %R
+}
+attributes #0 = { "null-pointer-is-valid"="true" }
+
 ; CHECK-LABEL: @test8(
 ; CHECK-NOT: load
 define i32 @test8(i32* %P) {

Modified: llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-addrspace.ll Mon Jul  9 15:27:23 2018
@@ -58,6 +58,23 @@ entry:
   ret void
 }
 
+; CHECK-LABEL: test_call_no_null_opt
+; CHECK: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK-NOT: addrspacecast
+; CHECK: call i32 @foo(i32* %{{.*}})
+define void @test_call_no_null_opt(i32 addrspace(1)* %out, i64 %x) #0 {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = call i32 @foo(i32* %arrayidx)
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  ret void
+}
+
 ; CHECK-LABEL: test_load_and_call
 ; CHECK: alloca
 ; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
@@ -80,6 +97,29 @@ entry:
   ret void
 }
 
+; CHECK-LABEL: test_load_and_call_no_null_opt
+; CHECK: alloca
+; CHECK: call void @llvm.memcpy.p0i8.p2i8.i64
+; CHECK: load i32, i32* %{{.*}}
+; CHECK: call i32 @foo(i32* %{{.*}})
+; CHECK-NOT: addrspacecast
+; CHECK-NOT: load i32, i32 addrspace(2)*
+define void @test_load_and_call_no_null_opt(i32 addrspace(1)* %out, i64 %x, i64 %y) #0 {
+entry:
+  %data = alloca [8 x i32], align 4
+  %0 = bitcast [8 x i32]* %data to i8*
+  call void @llvm.memcpy.p0i8.p2i8.i64(i8* align 4 %0, i8 addrspace(2)* align 4 bitcast ([8 x i32] addrspace(2)* @test.data to i8 addrspace(2)*), i64 32, i1 false)
+  %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %data, i64 0, i64 %x
+  %1 = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %x
+  store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
+  %2 = call i32 @foo(i32* %arrayidx)
+  %arrayidx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %y
+  store i32 %2, i32 addrspace(1)* %arrayidx2, align 4
+  ret void
+}
 
 declare void @llvm.memcpy.p0i8.p2i8.i64(i8* nocapture writeonly, i8 addrspace(2)* nocapture readonly, i64, i1)
 declare i32 @foo(i32* %x)
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/memcpy-from-global.ll Mon Jul  9 15:27:23 2018
@@ -67,6 +67,26 @@ define void @test2() {
   ret void
 }
 
+define void @test2_no_null_opt() #0 {
+  %A = alloca %T
+  %B = alloca %T
+  %a = bitcast %T* %A to i8*
+  %b = bitcast %T* %B to i8*
+
+; CHECK-LABEL: @test2_no_null_opt(
+
+; %A alloca is deleted
+; CHECK-NEXT: alloca [124 x i8]
+; CHECK-NEXT: getelementptr inbounds [124 x i8], [124 x i8]*
+
+; use @G instead of %A
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %{{.*}}, i8* align 16 getelementptr inbounds (%T, %T* @G, i64 0, i32 0)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a, i8* align 4 bitcast (%T* @G to i8*), i64 124, i1 false)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %b, i8* align 4 %a, i64 124, i1 false)
+  call void @bar(i8* %b)
+  ret void
+}
+
 define void @test2_addrspacecast() {
   %A = alloca %T
   %B = alloca %T
@@ -235,3 +255,5 @@ entry:
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* getelementptr inbounds ([1000000 x i8], [1000000 x i8]* @bbb, i32 0, i32 0), i8* %arraydecay, i64 3, i1 false)
   ret void
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstCombine/select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/select.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/select.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/select.ll Mon Jul  9 15:27:23 2018
@@ -385,6 +385,31 @@ define i32 @test16_neg2(i1 %C, i32 addrs
   ret i32 %V
 }
 
+;; It may be legal to load from a null address with null pointer valid attribute.
+define i32 @test16_no_null_opt(i1 %C, i32* %P) #0 {
+; CHECK-LABEL: @test16_no_null_opt(
+; CHECK-NEXT:    [[P2:%.*]] = select i1 [[C:%.*]], i32* [[P:%.*]], i32* null
+; CHECK-NEXT:    [[V:%.*]] = load i32, i32* [[P2]], align 4
+; CHECK-NEXT:    ret i32 [[V]]
+;
+  %P2 = select i1 %C, i32* %P, i32* null
+  %V = load i32, i32* %P2
+  ret i32 %V
+}
+
+define i32 @test16_no_null_opt_2(i1 %C, i32* %P) #0 {
+; CHECK-LABEL: @test16_no_null_opt_2(
+; CHECK-NEXT:    [[P2:%.*]] = select i1 [[C:%.*]], i32* null, i32* [[P:%.*]]
+; CHECK-NEXT:    [[V:%.*]] = load i32, i32* [[P2]], align 4
+; CHECK-NEXT:    ret i32 [[V]]
+;
+  %P2 = select i1 %C, i32* null, i32* %P
+  %V = load i32, i32* %P2
+  ret i32 %V
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
 define i1 @test17(i32* %X, i1 %C) {
 ; CHECK-LABEL: @test17(
 ; CHECK-NEXT:    [[RV1:%.*]] = icmp eq i32* [[X:%.*]], null

Modified: llvm/trunk/test/Transforms/InstCombine/store.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/store.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/store.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/store.ll Mon Jul  9 15:27:23 2018
@@ -28,6 +28,17 @@ define void @store_at_gep_off_null(i64 %
    ret void
 }
 
+define void @store_at_gep_off_no_null_opt(i64 %offset) #0 {
+   %ptr = getelementptr i32, i32 *null, i64 %offset
+   store i32 24, i32* %ptr
+   ret void
+; CHECK-LABEL: @store_at_gep_off_no_null_opt(i64 %offset)
+; CHECK-NEXT: %ptr = getelementptr i32, i32* null, i64 %offset
+; CHECK-NEXT: store i32 24, i32* %ptr
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
 ;; Simple sinking tests
 
 ; "if then else"

Modified: llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/strcpy_chk-64.ll Mon Jul  9 15:27:23 2018
@@ -13,6 +13,19 @@ entry:
   ret void
 }
 
+define void @func_no_null_opt(i8* %i) nounwind ssp #0 {
+; CHECK-LABEL: @func_no_null_opt(
+; CHECK: @__strcpy_chk(i8* %arraydecay, i8* %i, i64 32)
+entry:
+  %s = alloca [32 x i8], align 16
+  %arraydecay = getelementptr inbounds [32 x i8], [32 x i8]* %s, i32 0, i32 0
+  %call = call i8* @__strcpy_chk(i8* %arraydecay, i8* %i, i64 32)
+  call void @func2(i8* %arraydecay)
+  ret void
+}
+
 declare i8* @__strcpy_chk(i8*, i8*, i64) nounwind
 
 declare void @func2(i8*)
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstCombine/strlen-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/strlen-1.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/strlen-1.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/strlen-1.ll Mon Jul  9 15:27:23 2018
@@ -162,6 +162,17 @@ define i32 @test_no_simplify2(i32 %x) {
   ret i32 %hello_l
 }
 
+define i32 @test_no_simplify2_no_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify2_no_null_opt(
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i8], [7 x i8]* @null_hello, i32 0, i32 %x
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i32 @strlen(i8* [[HELLO_P]])
+; CHECK-NEXT:    ret i32 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i8], [7 x i8]* @null_hello, i32 0, i32 %x
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
 ; strlen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
 
 define i32 @test_no_simplify3(i32 %x) {
@@ -177,3 +188,17 @@ define i32 @test_no_simplify3(i32 %x) {
   ret i32 %hello_l
 }
 
+define i32 @test_no_simplify3_on_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify3_on_null_opt(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 15
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 [[AND]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i32 @strlen(i8* [[HELLO_P]])
+; CHECK-NEXT:    ret i32 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i8], [13 x i8]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i32 @strlen(i8* %hello_p)
+  ret i32 %hello_l
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/wcslen-1.ll Mon Jul  9 15:27:23 2018
@@ -166,6 +166,18 @@ define i64 @test_no_simplify2(i32 %x) {
   ret i64 %hello_l
 }
 
+define i64 @test_no_simplify2_no_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify2_no_null_opt(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %hello_p = getelementptr inbounds [7 x i32], [7 x i32]* @null_hello, i32 0, i32 %x
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
 ; wcslen(@null_hello_mid + (x & 15)) should not be simplified to a sub instruction.
 
 define i64 @test_no_simplify3(i32 %x) {
@@ -182,6 +194,20 @@ define i64 @test_no_simplify3(i32 %x) {
   ret i64 %hello_l
 }
 
+define i64 @test_no_simplify3_no_null_opt(i32 %x) #0 {
+; CHECK-LABEL: @test_no_simplify3_no_null_opt(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[AND]] to i64
+; CHECK-NEXT:    [[HELLO_P:%.*]] = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i64 0, i64 [[TMP1]]
+; CHECK-NEXT:    [[HELLO_L:%.*]] = call i64 @wcslen(i32* [[HELLO_P]])
+; CHECK-NEXT:    ret i64 [[HELLO_L]]
+;
+  %and = and i32 %x, 15
+  %hello_p = getelementptr inbounds [13 x i32], [13 x i32]* @null_hello_mid, i32 0, i32 %and
+  %hello_l = call i64 @wcslen(i32* %hello_p)
+  ret i64 %hello_l
+}
+
 @str16 = constant [1 x i16] [i16 0]
 
 define i64 @test_no_simplify4() {
@@ -192,3 +218,5 @@ define i64 @test_no_simplify4() {
   %l = call i64 @wcslen(i32* bitcast ([1 x i16]* @str16 to i32*))
   ret i64 %l
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/InstSimplify/compare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/compare.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/compare.ll (original)
+++ llvm/trunk/test/Transforms/InstSimplify/compare.ll Mon Jul  9 15:27:23 2018
@@ -185,6 +185,17 @@ define i1 @gep13(i8* %ptr) {
 ; CHECK-NEXT: ret i1 false
 }
 
+define i1 @gep13_no_null_opt(i8* %ptr) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep13_no_null_opt(
+; CHECK: getelementptr
+; CHECK: icmp
+; CHECK: ret
+  %x = getelementptr inbounds i8, i8* %ptr, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
 define i1 @gep14({ {}, i8 }* %ptr) {
 ; CHECK-LABEL: @gep14(
 ; We can't simplify this because the offset of one in the GEP actually doesn't
@@ -205,6 +216,17 @@ define i1 @gep15({ {}, [4 x {i8, i8}]}*
 ; CHECK-NEXT: ret i1 false
 }
 
+define i1 @gep15_no_null_opt({ {}, [4 x {i8, i8}]}* %ptr, i32 %y) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep15_no_null_opt(
+; CHECK: getelementptr
+; CHECK: icmp
+; CHECK: ret
+  %x = getelementptr inbounds { {}, [4 x {i8, i8}]}, { {}, [4 x {i8, i8}]}* %ptr, i32 0, i32 1, i32 %y, i32 1
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
 define i1 @gep16(i8* %ptr, i32 %a) {
 ; CHECK-LABEL: @gep16(
 ; We can prove this GEP is non-null because it is inbounds and because we know
@@ -216,6 +238,18 @@ define i1 @gep16(i8* %ptr, i32 %a) {
 ; CHECK-NEXT: ret i1 false
 }
 
+define i1 @gep16_no_null_opt(i8* %ptr, i32 %a) #0 {
+; We can't prove this GEP is non-null.
+; CHECK-LABEL: @gep16_no_null_opt(
+; CHECK getelementptr inbounds i8, i8* %ptr, i32 %b
+; CHECK: %cmp = icmp eq i8* %x, null
+; CHECK-NEXT: ret i1 %cmp
+  %b = or i32 %a, 1
+  %x = getelementptr inbounds i8, i8* %ptr, i32 %b
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
 define i1 @gep17() {
 ; CHECK-LABEL: @gep17(
   %alloca = alloca i32, align 4
@@ -712,6 +746,17 @@ define i1 @alloca_compare(i64 %idx) {
   ; CHECK: ret i1 false
 }
 
+define i1 @alloca_compare_no_null_opt(i64 %idx) #0 {
+; CHECK-LABEL: alloca_compare_no_null_opt(
+; CHECK: %sv = alloca { i32, i32, [124 x i32] }
+; CHECK: %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx
+; CHECK: %X = icmp eq i32* %cmp, null
+; CHECK: ret i1 %X
+  %sv = alloca { i32, i32, [124 x i32] }
+  %cmp = getelementptr inbounds { i32, i32, [124 x i32] }, { i32, i32, [124 x i32] }* %sv, i32 0, i32 2, i64 %idx
+  %X = icmp eq i32* %cmp, null
+  ret i1 %X
+}
 ; PR12075
 define i1 @infinite_gep() {
   ret i1 1
@@ -768,6 +813,19 @@ define i1 @alloca_gep(i64 %a, i64 %b) {
 ; CHECK-NEXT: ret i1 false
 }
 
+define i1 @alloca_gep_no_null_opt(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: @alloca_gep_no_null_opt(
+; We can't prove this GEP is non-null.
+; CHECK: alloca
+; CHECK: getelementptr
+; CHECK: icmp
+; CHECK: ret
+  %strs = alloca [1000 x [1001 x i8]], align 16
+  %x = getelementptr inbounds [1000 x [1001 x i8]], [1000 x [1001 x i8]]* %strs, i64 0, i64 %a, i64 %b
+  %cmp = icmp eq i8* %x, null
+  ret i1 %cmp
+}
+
 define i1 @non_inbounds_gep_compare(i64* %a) {
 ; CHECK-LABEL: @non_inbounds_gep_compare(
 ; Equality compares with non-inbounds GEPs can be folded.
@@ -865,6 +923,13 @@ define i1 @nonnull_arg(i32* nonnull %i)
 ; CHECK: ret i1 false
 }
 
+define i1 @nonnull_arg_no_null_opt(i32* nonnull %i) #0 {
+  %cmp = icmp eq i32* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_arg_no_null_opt
+; CHECK: ret i1 false
+}
+
 define i1 @nonnull_deref_arg(i32* dereferenceable(4) %i) {
   %cmp = icmp eq i32* %i, null
   ret i1 %cmp
@@ -872,6 +937,13 @@ define i1 @nonnull_deref_arg(i32* derefe
 ; CHECK: ret i1 false
 }
 
+define i1 @nonnull_deref_arg_no_null_opt(i32* dereferenceable(4) %i) #0 {
+  %cmp = icmp eq i32* %i, null
+  ret i1 %cmp
+; CHECK-LABEL: @nonnull_deref_arg_no_null_opt
+; CHECK-NEXT: icmp
+; CHECK: ret
+}
 define i1 @nonnull_deref_as_arg(i32 addrspace(1)* dereferenceable(4) %i) {
   %cmp = icmp eq i32 addrspace(1)* %i, null
   ret i1 %cmp
@@ -898,6 +970,15 @@ define i1 @returns_nonnull_deref() {
 ; CHECK: ret i1 false
 }
 
+define i1 @returns_nonnull_deref_no_null_opt () #0 {
+  %call = call dereferenceable(4) i32* @returns_nonnull_deref_helper()
+  %cmp = icmp eq i32* %call, null
+  ret i1 %cmp
+; CHECK-LABEL: @returns_nonnull_deref_no_null_opt
+; CHECK: icmp
+; CHECK: ret
+}
+
 declare dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
 define i1 @returns_nonnull_as_deref() {
   %call = call dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
@@ -1276,3 +1357,5 @@ define i1 @constant_fold_null_inttoptr()
   %x = icmp eq i32* null, inttoptr (i64 32 to i32*)
   ret i1 %x
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/LoopIdiom/pr28196.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopIdiom/pr28196.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopIdiom/pr28196.ll (original)
+++ llvm/trunk/test/Transforms/LoopIdiom/pr28196.ll Mon Jul  9 15:27:23 2018
@@ -24,3 +24,30 @@ for.body:
 ; CHECK-LABEL: define void @test1(
 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 null, i8* align 4 inttoptr (i64 4 to i8*), i64 24, i1 false)
 ; CHECK-NOT: store
+
+define void @test1_no_null_opt() #0 {
+entry:
+  br label %for.body.preheader
+
+for.body.preheader:                               ; preds = %for.cond
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.preheader
+  %indvars.iv = phi i32 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ]
+  %add.ptr3 = getelementptr inbounds i32, i32* null, i32 %indvars.iv
+  %add.ptr4 = getelementptr inbounds i32, i32* %add.ptr3, i32 1
+  %0 = load i32, i32* %add.ptr4, align 4
+  store i32 %0, i32* %add.ptr3, align 4
+  %indvars.iv.next = add nsw i32 %indvars.iv, 1
+  %exitcond = icmp ne i32 %indvars.iv.next, 6
+  br i1 %exitcond, label %for.body, label %for.body.preheader
+}
+
+; CHECK-LABEL: define void @test1_no_null_opt(
+; CHECK-NOT: call void @llvm.memcpy
+; CHECK: getelementptr
+; CHECK: getelementptr
+; CHECK: load
+; CHECK: store
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/LoopVersioning/lcssa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopVersioning/lcssa.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopVersioning/lcssa.ll (original)
+++ llvm/trunk/test/Transforms/LoopVersioning/lcssa.ll Mon Jul  9 15:27:23 2018
@@ -33,3 +33,40 @@ bb3.loopexit:
 bb3:
   ret void
 }
+
+define void @fill_no_null_opt(i8** %ls1.20, i8** %ls2.21, i8* %cse3.22) #0 {
+; CHECK-LABEL: fill_no_null_opt(
+; CHECK: bb1.lver.check:
+; CHECK: %lver.safe = or i1 %memcheck.conflict, %{{.*}}
+; CHECK:  br i1 %lver.safe, label %bb1.ph.lver.orig, label %bb1.ph
+bb1.ph:
+  %ls1.20.promoted = load i8*, i8** %ls1.20
+  %ls2.21.promoted = load i8*, i8** %ls2.21
+  br label %bb1
+
+bb1:
+  %_tmp302 = phi i8* [ %ls2.21.promoted, %bb1.ph ], [ %_tmp30, %bb1 ]
+  %_tmp281 = phi i8* [ %ls1.20.promoted, %bb1.ph ], [ %_tmp28, %bb1 ]
+  %_tmp14 = getelementptr i8, i8* %_tmp281, i16 -1
+  %_tmp15 = load i8, i8* %_tmp14
+  %add = add i8 %_tmp15, 1
+  store i8 %add, i8* %_tmp281
+  store i8 %add, i8* %_tmp302
+  %_tmp28 = getelementptr i8, i8* %_tmp281, i16 1
+  %_tmp30 = getelementptr i8, i8* %_tmp302, i16 1
+  br i1 false, label %bb1, label %bb3.loopexit
+
+bb3.loopexit:
+  %_tmp30.lcssa = phi i8* [ %_tmp30, %bb1 ]
+  %_tmp15.lcssa = phi i8 [ %_tmp15, %bb1 ]
+  %_tmp28.lcssa = phi i8* [ %_tmp28, %bb1 ]
+  store i8* %_tmp28.lcssa, i8** %ls1.20
+  store i8 %_tmp15.lcssa, i8* %cse3.22
+  store i8* %_tmp30.lcssa, i8** %ls2.21
+  br label %bb3
+
+bb3:
+  ret void
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/UnreachableEliminate.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/UnreachableEliminate.ll (original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/UnreachableEliminate.ll Mon Jul  9 15:27:23 2018
@@ -78,6 +78,28 @@ bb2:
   ret void
 }
 
+define void @test5_no_null_opt(i1 %cond, i8* %ptr) #0 {
+
+; CHECK-LABEL: test5_no_null_opt
+; CHECK: entry:
+; CHECK: %[[SEL:.*]] = select i1 %cond, i8* null, i8* %ptr
+; CHECK: store i8 2, i8* %[[SEL]]
+
+entry:
+  br i1 %cond, label %bb1, label %bb3
+
+bb3:
+ br label %bb2
+
+bb1:
+ br label %bb2
+
+bb2:
+  %ptr.2 = phi i8* [ %ptr, %bb3 ], [ null, %bb1 ]
+  store i8 2, i8* %ptr.2, align 8
+  ret void
+}
+
 ; CHECK-LABEL: test6
 ; CHECK: entry:
 ; CHECK-NOT: select
@@ -97,6 +119,25 @@ bb2:
   ret void
 }
 
+; CHECK-LABEL: test6_no_null_opt
+; CHECK: entry:
+; CHECK: %[[SEL:.*]] = select i1 %cond, i8* null, i8* %ptr
+; CHECK: store i8 2, i8* %[[SEL]]
+
+define void @test6_no_null_opt(i1 %cond, i8* %ptr) #0 {
+entry:
+  br i1 %cond, label %bb1, label %bb2
+
+bb1:
+  br label %bb2
+
+bb2:
+  %ptr.2 = phi i8* [ %ptr, %entry ], [ null, %bb1 ]
+  store i8 2, i8* %ptr.2, align 8
+  ret void
+}
+
+
 define i32 @test7(i1 %X) {
 entry:
   br i1 %X, label %if, label %else
@@ -127,3 +168,21 @@ else:
 }
 ; CHECK-LABEL: define void @test8(
 ; CHECK: call void %Y(
+
+define void @test8_no_null_opt(i1 %X, void ()* %Y) #0 {
+entry:
+  br i1 %X, label %if, label %else
+
+if:
+  br label %else
+
+else:
+  %phi = phi void ()* [ %Y, %entry ], [ null, %if ]
+  call void %phi()
+  ret void
+}
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+; CHECK-LABEL: define void @test8_no_null_opt(
+; CHECK: %[[SEL:.*]] = select i1 %X, void ()* null, void ()* %Y
+; CHECK: call void %[[SEL]]

Modified: llvm/trunk/test/Transforms/SimplifyCFG/invoke.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/invoke.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/invoke.ll (original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/invoke.ll Mon Jul  9 15:27:23 2018
@@ -47,6 +47,27 @@ lpad:
   unreachable
 }
 
+; CHECK-LABEL: @f2_no_null_opt(
+define i8* @f2_no_null_opt() nounwind uwtable ssp #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+; CHECK: invoke noalias i8* null()
+  %call = invoke noalias i8* null()
+          to label %invoke.cont unwind label %lpad
+
+; CHECK: invoke.cont:
+; CHECK: ret i8* %call
+invoke.cont:
+  ret i8* %call
+
+lpad:
+  %0 = landingpad { i8*, i32 }
+          filter [0 x i8*] zeroinitializer
+  %1 = extractvalue { i8*, i32 } %0, 0
+  tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind
+; CHECK: unreachable
+  unreachable
+}
+
 ; CHECK-LABEL: @f3(
 define i32 @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
 ; CHECK-NEXT: entry
@@ -137,3 +158,5 @@ lpad:
           cleanup
   ret void
 }
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/test/Transforms/SimplifyCFG/phi-undef-loadstore.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/phi-undef-loadstore.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/phi-undef-loadstore.ll (original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/phi-undef-loadstore.ll Mon Jul  9 15:27:23 2018
@@ -31,6 +31,37 @@ if.end7:
 ; CHECK: phi i32* [ %a, %if.then ], [ %c, %if.else ]
 }
 
+define i32 @test1_no_null_opt(i32* %a, i32 %b, i32* %c, i32 %d) nounwind #0 {
+entry:
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.else:                                          ; preds = %entry
+  %tobool3 = icmp eq i32 %d, 0
+  br i1 %tobool3, label %if.end7, label %if.then4
+
+if.then4:                                         ; preds = %if.else
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.else, %if.then4, %if.then
+  %x.0 = phi i32* [ %a, %if.then ], [ %c, %if.then4 ], [ null, %if.else ]
+  %tmp9 = load i32, i32* %x.0
+  ret i32 %tmp9
+
+; CHECK-LABEL: @test1_no_null_opt(
+; CHECK: if.then:
+; CHECK: if.else:
+; CHECK: if.then4:
+; CHECK: br label %if.end7
+; CHECK: if.end7:
+; CHECK-NEXT: phi i32* [ %a, %if.then ], [ %c, %if.then4 ], [ null, %if.else ]
+}
+
 define i32 @test2(i32* %a, i32 %b, i32* %c, i32 %d) nounwind {
 entry:
   %tobool = icmp eq i32 %b, 0
@@ -59,6 +90,35 @@ if.end7:
 ; CHECK-NOT: phi
 }
 
+define i32 @test2_no_null_opt(i32* %a, i32 %b, i32* %c, i32 %d) nounwind #0 {
+entry:
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.else:                                          ; preds = %entry
+  %tobool3 = icmp eq i32 %d, 0
+  br i1 %tobool3, label %if.end7, label %if.then4
+
+if.then4:                                         ; preds = %if.else
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.else, %if.then4, %if.then
+  %x.0 = phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
+  %tmp9 = load i32, i32* %x.0
+  ret i32 %tmp9
+; CHECK-LABEL: @test2_no_null_opt(
+; CHECK: if.then:
+; CHECK: if.else:
+; CHECK: if.then4:
+; CHECK: if.end7:
+; CHECK-NEXT: phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
+}
+
 define i32 @test3(i32* %a, i32 %b, i32* %c, i32 %d) nounwind {
 entry:
   %tobool = icmp eq i32 %b, 0
@@ -86,6 +146,36 @@ if.end7:
 ; CHECK: phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
 }
 
+define i32 @test3_no_null_opt(i32* %a, i32 %b, i32* %c, i32 %d) nounwind #0 {
+entry:
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.else:                                          ; preds = %entry
+  %tobool3 = icmp eq i32 %d, 0
+  br i1 %tobool3, label %if.end7, label %if.then4
+
+if.then4:                                         ; preds = %if.else
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.else, %if.then4, %if.then
+  %x.0 = phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
+  tail call void @bar() nounwind
+  %tmp9 = load i32, i32* %x.0
+  ret i32 %tmp9
+; CHECK-LABEL: @test3_no_null_opt(
+; CHECK: if.then:
+; CHECK: if.else:
+; CHECK: if.then4:
+; CHECK: if.end7:
+; CHECK-NEXT: phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
+}
+
 define i32 @test4(i32* %a, i32 %b, i32* %c, i32 %d) nounwind {
 entry:
   %tobool = icmp eq i32 %b, 0
@@ -113,3 +203,37 @@ if.end7:
 ; CHECK-LABEL: @test4(
 ; CHECK-NOT: phi
 }
+
+define i32 @test4_no_null_opt(i32* %a, i32 %b, i32* %c, i32 %d) nounwind #0 {
+entry:
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.else:                                          ; preds = %entry
+  %tobool3 = icmp eq i32 %d, 0
+  br i1 %tobool3, label %if.end7, label %if.then4
+
+if.then4:                                         ; preds = %if.else
+  tail call void @bar() nounwind
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.else, %if.then4, %if.then
+  %x.0 = phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
+  %gep = getelementptr i32, i32* %x.0, i32 10
+  %tmp9 = load i32, i32* %gep
+  %tmp10 = or i32 %tmp9, 1
+  store i32 %tmp10, i32* %gep
+  ret i32 %tmp9
+; CHECK-LABEL: @test4_no_null_opt(
+; CHECK: if.then:
+; CHECK: if.else:
+; CHECK: if.then4:
+; CHECK: if.end7:
+; CHECK-NEXT: phi i32* [ %a, %if.then ], [ null, %if.then4 ], [ null, %if.else ]
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }

Added: llvm/trunk/test/Transforms/SimplifyCFG/trap-no-null-opt-debugloc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/trap-no-null-opt-debugloc.ll?rev=336613&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/trap-no-null-opt-debugloc.ll (added)
+++ llvm/trunk/test/Transforms/SimplifyCFG/trap-no-null-opt-debugloc.ll Mon Jul  9 15:27:23 2018
@@ -0,0 +1,24 @@
+; RUN: opt -S -simplifycfg < %s | FileCheck %s
+define void @foo() nounwind ssp #0 !dbg !0 {
+; CHECK: store i32 42, i32* null
+; CHECK-NOT: call void @llvm.trap()
+; CHECK: ret void
+  store i32 42, i32* null, !dbg !5
+  ret void, !dbg !7
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!10}
+
+!0 = distinct !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2, file: !8, scope: !1, type: !3)
+!1 = !DIFile(filename: "foo.c", directory: "/private/tmp")
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "Apple clang version 3.0 (tags/Apple/clang-206.1) (based on LLVM 3.0svn)", isOptimized: true, emissionKind: FullDebug, file: !8, enums: !{}, retainedTypes: !{})
+!3 = !DISubroutineType(types: !4)
+!4 = !{null}
+!5 = !DILocation(line: 4, column: 2, scope: !6)
+!6 = distinct !DILexicalBlock(line: 3, column: 12, file: !8, scope: !0)
+!7 = !DILocation(line: 5, column: 1, scope: !6)
+!8 = !DIFile(filename: "foo.c", directory: "/private/tmp")
+!10 = !{i32 1, !"Debug Info Version", i32 3}

Modified: llvm/trunk/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll (original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll Mon Jul  9 15:27:23 2018
@@ -21,17 +21,44 @@ return:         ; preds = %entry
 ; CHECK: load volatile
 }
 
+define void @test1_no_null_opt(i32 %x) nounwind #0 {
+entry:
+        %0 = icmp eq i32 %x, 0          ; <i1> [#uses=1]
+        br i1 %0, label %bb, label %return
+
+bb:             ; preds = %entry
+        %1 = load volatile i32, i32* null
+        unreachable
+
+        br label %return
+return:         ; preds = %entry
+        ret void
+; CHECK-LABEL: @test1_no_null_opt(
+; CHECK: load volatile
+; CHECK: unreachable
+}
+
 ; rdar://7958343
 define void @test2() nounwind {
 entry:
         store i32 4,i32* null
         ret void
-        
+
 ; CHECK-LABEL: @test2(
 ; CHECK: call void @llvm.trap
 ; CHECK: unreachable
 }
 
+define void @test2_no_null_opt() nounwind #0 {
+entry:
+        store i32 4,i32* null
+        ret void
+; CHECK-LABEL: @test2_no_null_opt(
+; CHECK: store i32 4, i32* null
+; CHECK-NOT: call void @llvm.trap
+; CHECK: ret
+}
+
 ; PR7369
 define void @test3() nounwind {
 entry:
@@ -43,6 +70,16 @@ entry:
 ; CHECK: ret
 }
 
+define void @test3_no_null_opt() nounwind #0 {
+entry:
+        store volatile i32 4, i32* null
+        ret void
+
+; CHECK-LABEL: @test3_no_null_opt(
+; CHECK: store volatile i32 4, i32* null
+; CHECK: ret
+}
+
 ; Check store before unreachable.
 define void @test4(i1 %C, i32* %P) {
 ; CHECK-LABEL: @test4(
@@ -85,3 +122,4 @@ F:
   ret void
 }
 
+attributes #0 = { "null-pointer-is-valid"="true" }

Modified: llvm/trunk/unittests/Analysis/AliasAnalysisTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/AliasAnalysisTest.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/unittests/Analysis/AliasAnalysisTest.cpp (original)
+++ llvm/trunk/unittests/Analysis/AliasAnalysisTest.cpp Mon Jul  9 15:27:23 2018
@@ -156,7 +156,7 @@ protected:
 
     // Build the various AA results and register them.
     AC.reset(new AssumptionCache(F));
-    BAR.reset(new BasicAAResult(M.getDataLayout(), TLI, *AC));
+    BAR.reset(new BasicAAResult(M.getDataLayout(), F, TLI, *AC));
     AAR->addAAResult(*BAR);
 
     return *AAR;

Modified: llvm/trunk/unittests/Analysis/MemorySSA.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/MemorySSA.cpp?rev=336613&r1=336612&r2=336613&view=diff
==============================================================================
--- llvm/trunk/unittests/Analysis/MemorySSA.cpp (original)
+++ llvm/trunk/unittests/Analysis/MemorySSA.cpp Mon Jul  9 15:27:23 2018
@@ -50,7 +50,7 @@ protected:
 
     TestAnalyses(MemorySSATest &Test)
         : DT(*Test.F), AC(*Test.F), AA(Test.TLI),
-          BAA(Test.DL, Test.TLI, AC, &DT) {
+          BAA(Test.DL, *Test.F, Test.TLI, AC, &DT) {
       AA.addAAResult(BAA);
       MSSA = make_unique<MemorySSA>(*Test.F, &AA, &DT);
       Walker = MSSA->getWalker();




More information about the llvm-commits mailing list