Index: llvm/include/llvm/Analysis/AliasSetTracker.h
===================================================================
--- llvm/include/llvm/Analysis/AliasSetTracker.h
+++ llvm/include/llvm/Analysis/AliasSetTracker.h
@@ -134,6 +134,10 @@
       }
       delete this;
     }
+    void updateNoAliasProvenanceIfMatching(Value *Old, Value *New) {
+      if (AAInfo.NoAliasProvenance == Old)
+        AAInfo.NoAliasProvenance = New;
+    }
   };
 
   // Doubly linked list of nodes.
@@ -353,6 +357,25 @@
   // Map from pointers to their node
   PointerMapType PointerMap;
 
+  // FIXME: NOTE: when we get a callback, the resulting update might be _SLOW_
+  class ASTProvenanceCallbackVH final : public CallbackVH {
+    AliasSetTracker *AST;
+
+    void deleted() override;
+    void allUsesReplacedWith(Value *) override;
+
+  public:
+    ASTProvenanceCallbackVH(Value *V, AliasSetTracker *AST = nullptr);
+    ASTProvenanceCallbackVH &operator=(Value *V);
+  };
+
+  /// Traits to tell DenseMap that tell us how to compare and hash the value
+  /// handle.
+  struct ASTProvenanceCallbackVHDenseMapInfo : public DenseMapInfo<Value *> {};
+  using ProvenanceSetType =
+      DenseSet<ASTProvenanceCallbackVH, ASTProvenanceCallbackVHDenseMapInfo>;
+  ProvenanceSetType ProvenancePointers;
+
 public:
   /// Create an empty collection of AliasSets, and use the specified alias
   /// analysis object to disambiguate load and store addresses.
@@ -408,6 +431,19 @@
   /// tracker already knows about a value, it will ignore the request.
   void copyValue(Value *From, Value *To);
 
+  /// This method is used to remove a ptr_provenance pointer value from the
+  /// AliasSetTracker entirely. It should be used when an instruction is deleted
+  /// from the program to update the AST. If you don't use this, you would have
+  /// dangling pointers to deleted instructions.
+  void deleteProvenanceValue(Value *PtrVal);
+
+  /// This method should be used whenever a preexisting ptr_provenance value in
+  /// the program is copied or cloned, introducing a new value.  Note that it is
+  /// ok for clients that use this method to introduce the same value multiple
+  /// times: if the tracker already knows about a value, it will ignore the
+  /// request.
+  void copyProvenanceValue(Value *From, Value *To);
+
   using iterator = ilist<AliasSet>::iterator;
   using const_iterator = ilist<AliasSet>::const_iterator;
 
Index: llvm/include/llvm/Analysis/BasicAliasAnalysis.h
===================================================================
--- llvm/include/llvm/Analysis/BasicAliasAnalysis.h
+++ llvm/include/llvm/Analysis/BasicAliasAnalysis.h
@@ -56,6 +56,7 @@
   AssumptionCache &AC;
   DominatorTree *DT;
   PhiValues *PV;
+  unsigned RecurseLevel = 0;
 
 public:
   BasicAAResult(const DataLayout &DL, const Function &F,
Index: llvm/include/llvm/Analysis/ScopedNoAliasAA.h
===================================================================
--- llvm/include/llvm/Analysis/ScopedNoAliasAA.h
+++ llvm/include/llvm/Analysis/ScopedNoAliasAA.h
@@ -20,6 +20,7 @@
 #include <memory>
 
 namespace llvm {
+class DominatorTree;
 
 class Function;
 class MDNode;
@@ -30,13 +31,13 @@
   friend AAResultBase<ScopedNoAliasAAResult>;
 
 public:
+  ScopedNoAliasAAResult(DominatorTree *DT) : AAResultBase(), DT(DT) {}
+
   /// Handle invalidation events from the new pass manager.
   ///
   /// By definition, this result is stateless and so remains valid.
-  bool invalidate(Function &, const PreservedAnalyses &,
-                  FunctionAnalysisManager::Invalidator &) {
-    return false;
-  }
+  bool invalidate(Function &F, const PreservedAnalyses &PA,
+                  FunctionAnalysisManager::Invalidator &Inv);
 
   AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB,
                     AAQueryInfo &AAQI);
@@ -45,8 +46,24 @@
   ModRefInfo getModRefInfo(const CallBase *Call1, const CallBase *Call2,
                            AAQueryInfo &AAQI);
 
+  // FIXME: This interface can be removed once the legacy-pass-manager support
+  // is removed.
+  void setDT(DominatorTree *DT) { this->DT = DT; }
+
 private:
   bool mayAliasInScopes(const MDNode *Scopes, const MDNode *NoAlias) const;
+
+  bool findCompatibleNoAlias(const Value *P, const MDNode *ANoAlias,
+                             const MDNode *BNoAlias, const DataLayout &DL,
+                             SmallPtrSetImpl<const Value *> &Visited,
+                             SmallVectorImpl<Instruction *> &CompatibleSet,
+                             int Depth = 0);
+  bool noAliasByIntrinsic(const MDNode *ANoAlias, const Value *APtr,
+                          const MDNode *BNoAlias, const Value *BPtr,
+                          const CallBase *CallA, const CallBase *CallB,
+                          AAQueryInfo &AAQI);
+
+  DominatorTree *DT;
 };
 
 /// Analysis pass providing a never-invalidated alias analysis result.
@@ -70,12 +87,18 @@
 
   ScopedNoAliasAAWrapperPass();
 
-  ScopedNoAliasAAResult &getResult() { return *Result; }
+  ScopedNoAliasAAResult &getResult() {
+    setDT();
+    return *Result;
+  }
   const ScopedNoAliasAAResult &getResult() const { return *Result; }
 
   bool doInitialization(Module &M) override;
   bool doFinalization(Module &M) override;
   void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  void setDT();
 };
 
 //===--------------------------------------------------------------------===//
Index: llvm/include/llvm/IR/Instruction.h
===================================================================
--- llvm/include/llvm/IR/Instruction.h
+++ llvm/include/llvm/IR/Instruction.h
@@ -346,8 +346,15 @@
   void addAnnotationMetadata(StringRef Annotation);
 
   /// Sets the metadata on this instruction from the AAMDNodes structure.
+  /// NOTE: The ptr_provenance must be copied over explicitely using
+  /// 'setAAMetadataNoAliasProvenance'. This must only be done if the dominator
+  /// relationship between the ptr_provenance and this instruction holds.
   void setAAMetadata(const AAMDNodes &N);
 
+  /// Sets (only) the ptr_provenance. Normally used in combination with
+  /// setAAMetadata.
+  void setAAMetadataNoAliasProvenance(const AAMDNodes &N);
+
   /// Retrieve the raw weight values of a conditional branch or select.
   /// Returns true on success with profile weights filled in.
   /// Returns false if no metadata or invalid metadata was found.
Index: llvm/include/llvm/IR/Metadata.h
===================================================================
--- llvm/include/llvm/IR/Metadata.h
+++ llvm/include/llvm/IR/Metadata.h
@@ -1503,7 +1503,6 @@
 
 // Create wrappers for C Binding types (see CBindingWrapping.h).
 DEFINE_ISA_CONVERSION_FUNCTIONS(NamedMDNode, LLVMNamedMDNodeRef)
-
 } // end namespace llvm
 
 #endif // LLVM_IR_METADATA_H
Index: llvm/lib/Analysis/AliasSetTracker.cpp
===================================================================
--- llvm/lib/Analysis/AliasSetTracker.cpp
+++ llvm/lib/Analysis/AliasSetTracker.cpp
@@ -289,6 +289,7 @@
     I.second->eraseFromList();
 
   PointerMap.clear();
+  ProvenancePointers.clear();
 
   // The alias sets should all be clear now.
   AliasSets.clear();
@@ -351,6 +352,10 @@
 
   AliasSet::PointerRec &Entry = getEntryFor(Pointer);
 
+  if (AAInfo.NoAliasProvenance)
+    ProvenancePointers.insert(
+        ASTProvenanceCallbackVH(AAInfo.NoAliasProvenance, this));
+
   if (AliasAnyAS) {
     // At this point, the AST is saturated, so we only have one active alias
     // set. That means we already know which alias set we want to return, and
@@ -721,6 +726,65 @@
   return *this = ASTCallbackVH(V, AST);
 }
 
+//===----------------------------------------------------------------------===//
+//                     ASTProvenanceCallbackVH Class Implementation
+//===----------------------------------------------------------------------===//
+
+void AliasSetTracker::ASTProvenanceCallbackVH::deleted() {
+  assert(AST && "ASTCallbackVH called with a null AliasSetTracker!");
+  AST->deleteProvenanceValue(getValPtr());
+  // this now dangles!
+}
+
+void AliasSetTracker::ASTProvenanceCallbackVH::allUsesReplacedWith(Value *V) {
+  AST->copyProvenanceValue(getValPtr(), V);
+}
+
+AliasSetTracker::ASTProvenanceCallbackVH::ASTProvenanceCallbackVH(
+    Value *V, AliasSetTracker *ast)
+    : CallbackVH(V), AST(ast) {}
+
+AliasSetTracker::ASTProvenanceCallbackVH &
+AliasSetTracker::ASTProvenanceCallbackVH::operator=(Value *V) {
+  return *this = ASTProvenanceCallbackVH(V, AST);
+}
+
+void AliasSetTracker::deleteProvenanceValue(Value *PtrVal) {
+  // FIXME: slow algorithms ahead
+  ProvenanceSetType::iterator I = ProvenancePointers.find_as(PtrVal);
+  if (I == ProvenancePointers.end())
+    return; // nope
+
+  // iterate over all PointerRecords to update the AAMDNodes that contain this
+  // pointer
+  for (auto &AS : *this) {
+    for (auto &PR : AS) {
+      PR.updateNoAliasProvenanceIfMatching(PtrVal, nullptr);
+    }
+  }
+
+  ProvenancePointers.erase(I);
+}
+
+void AliasSetTracker::copyProvenanceValue(Value *From, Value *To) {
+  // FIXME: slow algorithms ahead
+  ProvenanceSetType::iterator I = ProvenancePointers.find_as(From);
+  if (I == ProvenancePointers.end())
+    return; // nope
+
+  // iterate over all PointerRecords to update the AAMDNodes that contain this
+  // pointer
+  for (auto &AS : *this) {
+    for (auto &PR : AS) {
+      PR.updateNoAliasProvenanceIfMatching(From, To);
+    }
+  }
+
+  // Update the set
+  ProvenancePointers.erase(I);
+  ProvenancePointers.insert(ASTProvenanceCallbackVH(To, this));
+}
+
 //===----------------------------------------------------------------------===//
 //                            AliasSetPrinter Pass
 //===----------------------------------------------------------------------===//
Index: llvm/lib/Analysis/ScopedNoAliasAA.cpp
===================================================================
--- llvm/lib/Analysis/ScopedNoAliasAA.cpp
+++ llvm/lib/Analysis/ScopedNoAliasAA.cpp
@@ -34,23 +34,51 @@
 #include "llvm/Analysis/ScopedNoAliasAA.h"
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/CaptureTracking.h"
 #include "llvm/Analysis/MemoryLocation.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/Dominators.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
 
 using namespace llvm;
 
+#define DEBUG_TYPE "scoped-noalias"
+
 // A handy option for disabling scoped no-alias functionality. The same effect
 // can also be achieved by stripping the associated metadata tags from IR, but
 // this option is sometimes more convenient.
-static cl::opt<bool> EnableScopedNoAlias("enable-scoped-noalias",
-                                         cl::init(true), cl::Hidden);
+static cl::opt<bool>
+    EnableScopedNoAlias("enable-scoped-noalias", cl::init(true), cl::Hidden,
+                        cl::desc("Enable use of scoped-noalias metadata"));
+
+static cl::opt<int>
+    MaxNoAliasDepth("scoped-noalias-max-depth", cl::init(12), cl::Hidden,
+                    cl::desc("Maximum depth for noalias intrinsic search"));
+
+static cl::opt<int> MaxNoAliasPointerCaptureDepth(
+    "scoped-noalias-max-pointer-capture-check", cl::init(320), cl::Hidden,
+    cl::desc("Maximum depth for noalias pointer capture search"));
+
+// A 'Undef'as 'NoAliasProvenance'  means 'no known extra information' about
+// the pointer provenance. In that case, we need to follow the real pointer
+// as it might contain extrainformation provided through llvm.noalias.arg.guard.
+// A absent (nullptr) 'NoAliasProvenance', indicates that this access does not
+// contain noalias provenance info.
+static const Value *selectMemoryProvenance(const MemoryLocation &Loc) {
+  if (!Loc.AATags.NoAliasProvenance ||
+      isa<UndefValue>(Loc.AATags.NoAliasProvenance))
+    return Loc.Ptr;
+  return Loc.AATags.NoAliasProvenance; // can be 'nullptr'
+}
 
 AliasResult ScopedNoAliasAAResult::alias(const MemoryLocation &LocA,
                                          const MemoryLocation &LocB,
@@ -69,6 +97,15 @@
   if (!mayAliasInScopes(BScopes, ANoAlias))
     return AliasResult::NoAlias;
 
+  LLVM_DEBUG(llvm::dbgs() << "ScopedNoAliasAAResult::alias\n");
+  if (noAliasByIntrinsic(ANoAlias, selectMemoryProvenance(LocA), BNoAlias,
+                         selectMemoryProvenance(LocB), nullptr, nullptr, AAQI))
+    return NoAlias;
+
+  if (noAliasByIntrinsic(BNoAlias, selectMemoryProvenance(LocB), ANoAlias,
+                         selectMemoryProvenance(LocA), nullptr, nullptr, AAQI))
+    return NoAlias;
+
   // If they may alias, chain to the next AliasAnalysis.
   return AAResultBase::alias(LocA, LocB, AAQI);
 }
@@ -79,12 +116,21 @@
   if (!EnableScopedNoAlias)
     return AAResultBase::getModRefInfo(Call, Loc, AAQI);
 
-  if (!mayAliasInScopes(Loc.AATags.Scope,
-                        Call->getMetadata(LLVMContext::MD_noalias)))
+  const MDNode *CSNoAlias = Call->getMetadata(LLVMContext::MD_noalias);
+  if (!mayAliasInScopes(Loc.AATags.Scope, CSNoAlias))
+    return ModRefInfo::NoModRef;
+
+  const MDNode *CSScopes = Call->getMetadata(LLVMContext::MD_alias_scope);
+  if (!mayAliasInScopes(CSScopes, Loc.AATags.NoAlias))
+    return ModRefInfo::NoModRef;
+
+  LLVM_DEBUG(llvm::dbgs() << "ScopedNoAliasAAResult::getModRefInfo - 1\n");
+  if (noAliasByIntrinsic(Loc.AATags.NoAlias, selectMemoryProvenance(Loc),
+                         CSNoAlias, nullptr, nullptr, Call, AAQI))
     return ModRefInfo::NoModRef;
 
-  if (!mayAliasInScopes(Call->getMetadata(LLVMContext::MD_alias_scope),
-                        Loc.AATags.NoAlias))
+  if (noAliasByIntrinsic(CSNoAlias, nullptr, Loc.AATags.NoAlias,
+                         selectMemoryProvenance(Loc), Call, nullptr, AAQI))
     return ModRefInfo::NoModRef;
 
   return AAResultBase::getModRefInfo(Call, Loc, AAQI);
@@ -96,12 +142,22 @@
   if (!EnableScopedNoAlias)
     return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
 
-  if (!mayAliasInScopes(Call1->getMetadata(LLVMContext::MD_alias_scope),
-                        Call2->getMetadata(LLVMContext::MD_noalias)))
+  const MDNode *CS1Scopes = Call1->getMetadata(LLVMContext::MD_alias_scope);
+  const MDNode *CS2Scopes = Call2->getMetadata(LLVMContext::MD_alias_scope);
+  const MDNode *CS1NoAlias = Call1->getMetadata(LLVMContext::MD_noalias);
+  const MDNode *CS2NoAlias = Call2->getMetadata(LLVMContext::MD_noalias);
+  if (!mayAliasInScopes(CS1Scopes, Call2->getMetadata(LLVMContext::MD_noalias)))
+    return ModRefInfo::NoModRef;
+
+  if (!mayAliasInScopes(CS2Scopes, Call1->getMetadata(LLVMContext::MD_noalias)))
     return ModRefInfo::NoModRef;
 
-  if (!mayAliasInScopes(Call2->getMetadata(LLVMContext::MD_alias_scope),
-                        Call1->getMetadata(LLVMContext::MD_noalias)))
+  if (noAliasByIntrinsic(CS1NoAlias, nullptr, CS2NoAlias, nullptr, Call1, Call2,
+                         AAQI))
+    return ModRefInfo::NoModRef;
+
+  if (noAliasByIntrinsic(CS2NoAlias, nullptr, CS1NoAlias, nullptr, Call2, Call1,
+                         AAQI))
     return ModRefInfo::NoModRef;
 
   return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
@@ -146,17 +202,501 @@
   return true;
 }
 
+bool ScopedNoAliasAAResult::findCompatibleNoAlias(
+    const Value *P, const MDNode *ANoAlias, const MDNode *BNoAlias,
+    const DataLayout &DL, SmallPtrSetImpl<const Value *> &Visited,
+    SmallVectorImpl<Instruction *> &CompatibleSet, int Depth) {
+  // When a pointer is derived from multiple noalias calls, there are two
+  // potential reasons:
+  //   1. The path of derivation is uncertain (because of a select, PHI, etc.).
+  //   2. Some noalias calls are derived from other noalias calls.
+  // Logically, we need to treat (1) as an "and" and (2) as an "or" when
+  // checking for scope compatibility. If we don't know from which noalias call
+  // a pointer is derived, then we need to require compatibility with all of
+  // them. If we're derived from a noalias call that is derived from another
+  // noalias call, then we need the ability to effectively ignore the inner one
+  // in favor of the outer one (thus, we only need compatibility with one or
+  // the other).
+  //
+  // Scope compatibility means that, as with the noalias metadata, within each
+  // domain, the set of noalias intrinsic scopes is a subset of the noalias
+  // scopes.
+  //
+  // Given this, we check compatibility of the relevant sets of noalias calls
+  // from which LocA.Ptr might derive with both LocA.AATags.NoAlias and
+  // LocB.AATags.NoAlias, and LocB.Ptr does not derive from any of the noalias
+  // calls in some set, then we can conclude NoAlias.
+  //
+  // So if we have:
+  //   noalias1  noalias3
+  //      |         |
+  //   noalias2  noalias4
+  //      |         |
+  //       \       /
+  //        \     /
+  //         \   /
+  //          \ /
+  //         select
+  //           |
+  //        noalias5
+  //           |
+  //        noalias6
+  //           |
+  //          PtrA
+  //
+  //  - If PtrA is compatible with noalias6, and PtrB is also compatible,
+  //    but does not derive from noalias6, then NoAlias.
+  //  - If PtrA is compatible with noalias5, and PtrB is also compatible,
+  //    but does not derive from noalias5, then NoAlias.
+  //  - If PtrA is compatible with noalias2 and noalias4, and PtrB is also
+  //    compatible, but does not derive from either, then NoAlias.
+  //  - If PtrA is compatible with noalias2 and noalias3, and PtrB is also
+  //    compatible, but does not derive from either, then NoAlias.
+  //  - If PtrA is compatible with noalias1 and noalias4, and PtrB is also
+  //    compatible, but does not derive from either, then NoAlias.
+  //  - If PtrA is compatible with noalias1 and noalias3, and PtrB is also
+  //    compatible, but does not derive from either, then NoAlias.
+  //
+  //  We don't need, or want, to explicitly build N! sets to check for scope
+  //  compatibility. Instead, recurse through the tree of underlying objects.
+
+  SmallVector<Instruction *, 8> NoAliasCalls;
+  P = getUnderlyingObject(P, 0, &NoAliasCalls);
+
+  // If we've already visited this underlying value (likely because this is a
+  // PHI that depends on itself, directly or indirectly), we must not have
+  // returned false the first time, so don't do so this time either.
+  if (!Visited.insert(P).second)
+    return true;
+
+  auto getNoAliasScopeMDNode = [](IntrinsicInst *II) {
+    return dyn_cast<MDNode>(
+        cast<MetadataAsValue>(
+            II->getOperand(II->getIntrinsicID() == Intrinsic::provenance_noalias
+                               ? Intrinsic::ProvenanceNoAliasScopeArg
+                               : Intrinsic::NoAliasScopeArg))
+            ->getMetadata());
+  };
+
+  // Our pointer is derived from P, with NoAliasCalls along the way.
+  // Compatibility with any of them is fine.
+  auto NAI = find_if(NoAliasCalls, [&](Instruction *A) {
+    return !mayAliasInScopes(getNoAliasScopeMDNode(cast<IntrinsicInst>(A)),
+                             ANoAlias) &&
+           !mayAliasInScopes(getNoAliasScopeMDNode(cast<IntrinsicInst>(A)),
+                             BNoAlias);
+  });
+  if (NAI != NoAliasCalls.end()) {
+    CompatibleSet.push_back(*NAI);
+    return true;
+  }
+
+  // We've not found a compatible noalias call, but we might be able to keep
+  // looking. If this underlying object is really a PHI or a select, we can
+  // check the incoming values. They all need to be compatible, and if so, we
+  // can take the union of all of the compatible noalias calls as the set to
+  // return for further validation.
+  SmallVector<const Value *, 8> Children;
+  if (const auto *SI = dyn_cast<SelectInst>(P)) {
+    Children.push_back(SI->getTrueValue());
+    Children.push_back(SI->getFalseValue());
+  } else if (const auto *PN = dyn_cast<PHINode>(P)) {
+    for (Value *IncommingValue : PN->incoming_values())
+      Children.push_back(IncommingValue);
+  }
+
+  if (Children.empty() || Depth == MaxNoAliasDepth)
+    return false;
+
+  SmallPtrSet<const Value *, 16> ChildVisited;
+  SmallVector<Instruction *, 8> ChildCompatSet;
+  for (auto &C : Children) {
+    ChildVisited.clear();
+    ChildVisited.insert(Visited.begin(), Visited.end());
+    ChildVisited.insert(P);
+
+    ChildCompatSet.clear();
+    if (!findCompatibleNoAlias(C, ANoAlias, BNoAlias, DL, ChildVisited,
+                               ChildCompatSet, Depth + 1))
+      return false;
+
+    CompatibleSet.insert(CompatibleSet.end(), ChildCompatSet.begin(),
+                         ChildCompatSet.end());
+  }
+
+  // All children were compatible, and we've added them to CompatibleSet.
+  return true;
+}
+
+bool ScopedNoAliasAAResult::noAliasByIntrinsic(
+    const MDNode *ANoAlias, const Value *APtr, const MDNode *BNoAlias,
+    const Value *BPtr, const CallBase *CallA, const CallBase *CallB,
+    AAQueryInfo &AAQI) {
+  LLVM_DEBUG(llvm::dbgs() << ">ScopedNoAliasAAResult::noAliasByIntrinsic:{"
+                          << (const void *)ANoAlias << "," << (const void *)APtr
+                          << "},{" << (const void *)BNoAlias << ","
+                          << (const void *)BPtr << "}\n");
+  if (!ANoAlias || !BNoAlias)
+    return false;
+
+  if (CallA) {
+    // We're querying a callsite against something else, where we want to know
+    // if the callsite (CallA) is derived from some noalias call(s) and the
+    // other thing is not derived from those noalias call(s). This can be
+    // determined only if CallA only accesses memory through its arguments.
+    FunctionModRefBehavior MRB = getModRefBehavior(CallA);
+    if (MRB != FMRB_OnlyAccessesArgumentPointees &&
+        MRB != FMRB_OnlyReadsArgumentPointees)
+      return false;
+
+    LLVM_DEBUG(dbgs() << "SNA: CSA: " << *CallA << "\n");
+    // Since the memory-access behavior of CallA is determined only by its
+    // arguments, we can answer this query in the affirmative if we can prove a
+    // lack of aliasing for all pointer arguments.
+    for (Value *Arg : CallA->args()) {
+      if (!Arg->getType()->isPointerTy())
+        continue;
+
+      if (!noAliasByIntrinsic(ANoAlias, Arg, BNoAlias, BPtr, nullptr, CallB,
+                              AAQI)) {
+        LLVM_DEBUG(dbgs() << "SNA: CSA: noalias fail for arg: " << *Arg
+                          << "\n");
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  const auto *AInst = dyn_cast<Instruction>(APtr);
+  if (!AInst || !AInst->getParent())
+    return false;
+  const DataLayout &DL = AInst->getParent()->getModule()->getDataLayout();
+
+  if (!CallB && !BPtr)
+    return false;
+
+  LLVM_DEBUG(dbgs() << "SNA: A: " << *APtr << "\n");
+  LLVM_DEBUG(dbgs() << "SNB: "; if (CallB) dbgs() << "CSB: " << *CallB;
+             else if (BPtr) dbgs() << "B: " << *BPtr;
+             else dbgs() << "B: nullptr"; dbgs() << "\n");
+
+  SmallPtrSet<const Value *, 8> Visited;
+  SmallVector<Instruction *, 8> CompatibleSet;
+  if (!findCompatibleNoAlias(APtr, ANoAlias, BNoAlias, DL, Visited,
+                             CompatibleSet))
+    return false;
+
+  assert(!CompatibleSet.empty() &&
+         "Fould an empty set of compatible intrinsics?");
+
+  LLVM_DEBUG(dbgs() << "SNA: Found a compatible set!\n");
+#ifndef NDEBUG
+  for (auto &C : CompatibleSet)
+    LLVM_DEBUG(dbgs() << "\t" << *C << "\n");
+  LLVM_DEBUG(dbgs() << "\n");
+#endif
+
+  // We have a set of compatible noalias calls (compatible with the scopes from
+  // both LocA and LocB) from which LocA.Ptr potentially derives. We now need
+  // to make sure that LocB.Ptr does not derive from any in that set. For
+  // correctness, there cannot be a depth limit here (if a pointer is derived
+  // from a noalias call, we must know).
+  SmallVector<const Value *, 8> BObjs;
+  SmallVector<Instruction *, 8> BNoAliasCalls;
+  if (CallB) {
+    for (Value *Arg : CallB->args())
+      getUnderlyingObjects(Arg, BObjs, nullptr, 0, &BNoAliasCalls);
+  } else {
+    getUnderlyingObjects(const_cast<Value *>(BPtr), BObjs, nullptr, 0,
+                         &BNoAliasCalls);
+  }
+
+  LLVM_DEBUG(dbgs() << "SNA: B/CSB noalias:\n");
+#ifndef NDEBUG
+  for (auto &B : BNoAliasCalls)
+    LLVM_DEBUG(dbgs() << "\t" << *B << "\n");
+  LLVM_DEBUG(dbgs() << "\n");
+#endif
+
+  // We need to check now if any compatible llvm.provenance.noalias call is
+  // potentially using the same 'P' object as one of the 'BNoAliasCalls'.
+  // If this is true for at least one entry, we must bail out and assume
+  // 'may_alias'
+
+  {
+    MDNode *NoAliasUnknownScopeMD =
+        AInst->getParent()->getParent()->getMetadata("noalias");
+
+    const struct {
+      unsigned IdentifyPObjIdArg;
+      unsigned ScopeArg;
+      unsigned IdentifyPArg;
+    } ProvNoAlias[2] = {{Intrinsic::NoAliasIdentifyPObjIdArg,
+                         Intrinsic::NoAliasScopeArg,
+                         Intrinsic::NoAliasIdentifyPArg},
+                        {Intrinsic::ProvenanceNoAliasIdentifyPObjIdArg,
+                         Intrinsic::ProvenanceNoAliasScopeArg,
+                         Intrinsic::ProvenanceNoAliasIdentifyPArg}};
+    for (Instruction *CA : CompatibleSet) {
+      LLVM_DEBUG(llvm::dbgs() << "- CA:" << *CA << "\n");
+      assert(isa<IntrinsicInst>(CA) &&
+             (cast<IntrinsicInst>(CA)->getIntrinsicID() ==
+                  llvm::Intrinsic::provenance_noalias ||
+              cast<IntrinsicInst>(CA)->getIntrinsicID() ==
+                  llvm::Intrinsic::noalias));
+      const int CA_IsProv = cast<IntrinsicInst>(CA)->getIntrinsicID() ==
+                                    llvm::Intrinsic::provenance_noalias
+                                ? 1
+                                : 0;
+      for (Instruction *CB : BNoAliasCalls) {
+        LLVM_DEBUG(llvm::dbgs() << "- CB:" << *CB << "\n");
+        assert(isa<IntrinsicInst>(CB) &&
+               (cast<IntrinsicInst>(CB)->getIntrinsicID() ==
+                    llvm::Intrinsic::provenance_noalias ||
+                cast<IntrinsicInst>(CB)->getIntrinsicID() ==
+                    llvm::Intrinsic::noalias));
+        const int CB_IsProv = cast<IntrinsicInst>(CB)->getIntrinsicID() ==
+                                      llvm::Intrinsic::provenance_noalias
+                                  ? 1
+                                  : 0;
+
+        // With the llvm.provenance.noalias version, we have different parts
+        // that can represent a P:
+        // - the actual 'identifyP' address (or an offset vs an optimized away
+        //   alloca)
+        // - the objectId (objectId's currently represent an offset to the
+        //   original alloca of the object)
+        // - the scope (different scopes = different objects; with the exception
+        //   of the 'unknown scope' an unknown scope can potentially be the same
+        //   as a real variable scope.
+        // If any of these are different, the P will not alias => *P will also
+        // not alias
+
+        // Let's start with the fast checks first;
+
+        // Same call ?
+        if (CA == CB) {
+          LLVM_DEBUG(llvm::dbgs() << "SNA == SNB\n");
+          return false;
+        }
+
+        // - different objectId ?
+        {
+          // check ObjId first: if the obj id's (aka, offset in the object) are
+          // different, they represent different objects
+          auto ObjIdA =
+              cast<ConstantInt>(
+                  CA->getOperand(ProvNoAlias[CA_IsProv].IdentifyPObjIdArg))
+                  ->getZExtValue();
+          auto ObjIdB =
+              cast<ConstantInt>(
+                  CB->getOperand(ProvNoAlias[CB_IsProv].IdentifyPObjIdArg))
+                  ->getZExtValue();
+          if (ObjIdA != ObjIdB) {
+            LLVM_DEBUG(llvm::dbgs() << "SNA.ObjId != SNB.ObjId\n");
+            continue;
+          }
+        }
+
+        // Different Scope ? (except for unknown scope)
+        {
+          bool isDifferentPByScope = true;
+          auto *CASnaScope = CA->getOperand(ProvNoAlias[CA_IsProv].ScopeArg);
+          auto *CBSnaScope = CB->getOperand(ProvNoAlias[CB_IsProv].ScopeArg);
+          if (CASnaScope == CBSnaScope) {
+            // compatibility check below will resolve
+            isDifferentPByScope = false;
+          } else {
+            if (NoAliasUnknownScopeMD) {
+              if ((cast<MetadataAsValue>(CASnaScope)->getMetadata() ==
+                   NoAliasUnknownScopeMD) ||
+                  (cast<MetadataAsValue>(CBSnaScope)->getMetadata() ==
+                   NoAliasUnknownScopeMD)) {
+                isDifferentPByScope = false;
+              }
+            }
+          }
+          if (isDifferentPByScope) {
+            LLVM_DEBUG(llvm::dbgs()
+                       << "SNA.Scope != SNB.Scope (and not 'unknown scope')\n");
+            continue;
+          }
+        }
+
+        // Different 'P' ?
+        {
+          Value *P_A = CA->getOperand(ProvNoAlias[CA_IsProv].IdentifyPArg);
+          Value *P_B = CB->getOperand(ProvNoAlias[CA_IsProv].IdentifyPArg);
+
+          if (P_A == P_B) {
+            LLVM_DEBUG(dbgs() << " SNA.Scope == SNB.Scope, SNA.P == SNB.P\n");
+            return false;
+          }
+
+          if (auto *CP_A = dyn_cast<Constant>(P_A)) {
+            if (auto *CP_B = dyn_cast<Constant>(P_B)) {
+              CP_B = ConstantExpr::getBitCast(CP_B, CP_A->getType());
+              Constant *Cmp =
+                  ConstantExpr::getCompare(CmpInst::ICMP_NE, CP_A, CP_B, true);
+              if (Cmp && Cmp->isNullValue()) {
+                LLVM_DEBUG(dbgs() << " SNA.Scope == SNB.Scope, !(SNA.P != "
+                                     "SNB.P) as constant\n");
+                return false;
+              }
+            }
+          }
+          // Check if P_A.addr and P_B.addr alias. If they don't, they describe
+          // different pointers.
+          LLVM_DEBUG(llvm::dbgs()
+                     << " SNA.P=" << *P_A << ", SNB.P=" << *P_B << "\n");
+          AAMDNodes P_A_Metadata;
+          AAMDNodes P_B_Metadata;
+          CA->getAAMetadata(P_A_Metadata);
+          CB->getAAMetadata(P_B_Metadata);
+
+          // The ptr_provenance is not handled in the
+          // Instruction::getAAMetadata for intrinsics
+          if (CA_IsProv) {
+            P_A_Metadata.NoAliasProvenance = CA->getOperand(
+                Intrinsic::ProvenanceNoAliasIdentifyPProvenanceArg);
+          }
+          if (CB_IsProv) {
+            P_B_Metadata.NoAliasProvenance = CB->getOperand(
+                Intrinsic::ProvenanceNoAliasIdentifyPProvenanceArg);
+          }
+
+          // Check with 1 unit
+          MemoryLocation ML_P_A(P_A, 1ull, P_A_Metadata);
+          MemoryLocation ML_P_B(P_B, 1ull, P_B_Metadata);
+          if (getBestAAResults().alias(ML_P_A, ML_P_B, AAQI) !=
+              AliasResult::NoAlias) {
+            LLVM_DEBUG(llvm::dbgs() << " P ... may alias\n");
+            return false;
+          }
+          LLVM_DEBUG(llvm::dbgs() << " P is NoAlias\n");
+          continue;
+        }
+      }
+    }
+  }
+
+  // The noalias scope from the compatible intrinsics are really identified by
+  // their scope argument, and we need to make sure that LocB.Ptr is not only
+  // not derived from the calls currently in CompatibleSet, but also from any
+  // other intrinsic with the same scope. We can't just search the list of
+  // noalias intrinsics in BNoAliasCalls because we care not just about those
+  // direct dependence, but also dependence through capturing. Metadata
+  // do not have use lists, but MetadataAsValue objects do (and they are
+  // uniqued), so we can search their use list. As a result, however,
+  // correctness demands that the scope list has only one element (so that we
+  // can find all uses of that scope by noalias intrinsics by looking at the
+  // use list of the associated scope list).
+  SmallPtrSet<Instruction *, 8> CompatibleSetMembers(CompatibleSet.begin(),
+                                                     CompatibleSet.end());
+  SmallVector<MetadataAsValue *, 8> CompatibleSetMVs;
+  for (auto &C : CompatibleSet) {
+    CompatibleSetMVs.push_back(cast<MetadataAsValue>(
+        C->getOperand(cast<IntrinsicInst>(C)->getIntrinsicID() ==
+                              Intrinsic::provenance_noalias
+                          ? Intrinsic::ProvenanceNoAliasScopeArg
+                          : Intrinsic::NoAliasScopeArg)));
+  }
+  for (auto &MV : CompatibleSetMVs)
+    for (Use &U : MV->uses())
+      if (auto *UI = dyn_cast<Instruction>(U.getUser())) {
+        // Skip noalias declarations
+        if (auto *CB = dyn_cast<CallBase>(UI))
+          if (CB->getIntrinsicID() == Intrinsic::noalias_decl)
+            continue;
+        if (CompatibleSetMembers.insert(UI).second) {
+          CompatibleSet.push_back(UI);
+          LLVM_DEBUG(dbgs() << "SNA: Adding to compatible set based on MD use: "
+                            << *UI << "\n");
+        }
+      }
+
+  LLVM_DEBUG(dbgs() << "SNA: B does not derive from the compatible set!\n");
+
+  // Note: This can be removed when legacy-pass-manager support is removed;
+  // BasicAA always has a DT available, and only under the hack where this is
+  // an immutable pass, not a function pass, might we not have one.
+  LLVM_DEBUG(dbgs() << "SNA: DT is " << (DT ? "available" : "unavailable")
+                    << "\n");
+
+  // We now know that LocB.Ptr does not derive from any of the noalias calls in
+  // CompatibleSet directly. We do, however, need to make sure that it cannot
+  // derive from them by capture.
+  for (auto &V : BObjs) {
+    // If the underlying object is not an instruction, then it can't be
+    // capturing the output value of an instruction (specifically, the noalias
+    // intrinsic call), and we can ignore it.
+    auto *I = dyn_cast<Instruction>(V);
+    if (!I)
+      continue;
+    if (isIdentifiedFunctionLocal(I))
+      continue;
+
+    LLVM_DEBUG(dbgs() << "SNA: Capture check for B/CSB UO: " << *I << "\n");
+
+    // If the value from the noalias intrinsic has been captured prior to the
+    // instruction defining the underlying object, then LocB.Ptr might yet be
+    // derived from the return value of the noalias intrinsic, and we cannot
+    // conclude anything about the aliasing.
+    for (auto &C : CompatibleSet)
+      if (PointerMayBeCapturedBefore(C, /* ReturnCaptures */ false,
+                                     /* StoreCaptures */ false, I, DT,
+                                     /* IncludeI */ false,
+                                     MaxNoAliasPointerCaptureDepth)) {
+        LLVM_DEBUG(dbgs() << "SNA: Pointer " << *C << " might be captured!\n");
+        return false;
+      }
+  }
+
+  if (CallB) {
+    FunctionModRefBehavior MRB = getModRefBehavior(CallB);
+    if (MRB != FMRB_OnlyAccessesArgumentPointees &&
+        MRB != FMRB_OnlyReadsArgumentPointees) {
+      // If we're querying against a callsite, and it might read from memory
+      // not based on its arguments, then we need to check whether or not the
+      // relevant noalias results have been captured prior to the callsite.
+      for (auto &C : CompatibleSet)
+        if (PointerMayBeCapturedBefore(C, /* ReturnCaptures */ false,
+                                       /* StoreCaptures */ false, CallB, DT)) {
+          LLVM_DEBUG(dbgs()
+                     << "SNA: CSB: Pointer " << *C << " might be captured!\n");
+          return false;
+        }
+    }
+  }
+
+  LLVM_DEBUG(dbgs() << " SNA: noalias!\n");
+  return true;
+}
+
 AnalysisKey ScopedNoAliasAA::Key;
 
+bool ScopedNoAliasAAResult::invalidate(
+    Function &F, const PreservedAnalyses &PA,
+    FunctionAnalysisManager::Invalidator &Inv) {
+  if (Inv.invalidate<DominatorTreeAnalysis>(F, PA))
+    return true;
+
+  return false;
+}
+
 ScopedNoAliasAAResult ScopedNoAliasAA::run(Function &F,
                                            FunctionAnalysisManager &AM) {
-  return ScopedNoAliasAAResult();
+  return ScopedNoAliasAAResult(&AM.getResult<DominatorTreeAnalysis>(F));
 }
 
 char ScopedNoAliasAAWrapperPass::ID = 0;
 
-INITIALIZE_PASS(ScopedNoAliasAAWrapperPass, "scoped-noalias-aa",
-                "Scoped NoAlias Alias Analysis", false, true)
+INITIALIZE_PASS_BEGIN(ScopedNoAliasAAWrapperPass, "scoped-noalias-aa",
+                      "Scoped NoAlias Alias Analysis", false, true)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_END(ScopedNoAliasAAWrapperPass, "scoped-noalias-aa",
+                    "Scoped NoAlias Alias Analysis", false, true)
 
 ImmutablePass *llvm::createScopedNoAliasAAWrapperPass() {
   return new ScopedNoAliasAAWrapperPass();
@@ -167,7 +707,7 @@
 }
 
 bool ScopedNoAliasAAWrapperPass::doInitialization(Module &M) {
-  Result.reset(new ScopedNoAliasAAResult());
+  Result.reset(new ScopedNoAliasAAResult(nullptr));
   return false;
 }
 
@@ -176,6 +716,12 @@
   return false;
 }
 
+void ScopedNoAliasAAWrapperPass::setDT() {
+  if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
+    Result->setDT(&DTWP->getDomTree());
+}
+
 void ScopedNoAliasAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
+  AU.addUsedIfAvailable<AAResultsWrapperPass>();
 }
Index: llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
===================================================================
--- llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -113,6 +113,7 @@
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/InitializePasses.h"
@@ -522,6 +523,21 @@
 }
 
 void Instruction::getAAMetadata(AAMDNodes &N, bool Merge) const {
+  auto mergeProvenance = [](AAMDNodes &N, Value *rhs) {
+    if (rhs && isa<UndefValue>(rhs))
+      rhs = nullptr;
+    if (N.NoAliasProvenance && isa<UndefValue>(N.NoAliasProvenance))
+      N.NoAliasProvenance = nullptr;
+
+    if (N.NoAliasProvenance == rhs)
+      return;
+
+    // ptr provenance differs - clean NoAlias scope information
+    N.NoAliasProvenance = nullptr;
+    N.NoAlias = nullptr;
+    N.Scope = nullptr;
+  };
+
   if (Merge) {
     N.TBAA =
         MDNode::getMostGenericTBAA(N.TBAA, getMetadata(LLVMContext::MD_tbaa));
@@ -536,6 +552,20 @@
     N.Scope = getMetadata(LLVMContext::MD_alias_scope);
     N.NoAlias = getMetadata(LLVMContext::MD_noalias);
   }
+
+  Value *NoAliasProvenance = nullptr;
+  if (const LoadInst *LI = dyn_cast<LoadInst>(this)) {
+    if (LI->hasNoaliasProvenanceOperand())
+      NoAliasProvenance = LI->getNoaliasProvenanceOperand();
+  } else if (const StoreInst *SI = dyn_cast<StoreInst>(this)) {
+    if (SI->hasNoaliasProvenanceOperand())
+      NoAliasProvenance = SI->getNoaliasProvenanceOperand();
+  }
+  if (Merge) {
+    mergeProvenance(N, NoAliasProvenance);
+  } else {
+    N.NoAliasProvenance = NoAliasProvenance;
+  }
 }
 
 static const MDNode *createAccessTag(const MDNode *AccessType) {
Index: llvm/lib/IR/Metadata.cpp
===================================================================
--- llvm/lib/IR/Metadata.cpp
+++ llvm/lib/IR/Metadata.cpp
@@ -38,6 +38,7 @@
 #include "llvm/IR/GlobalObject.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/Module.h"
@@ -1365,7 +1366,23 @@
   setMetadata(LLVMContext::MD_tbaa, N.TBAA);
   setMetadata(LLVMContext::MD_tbaa_struct, N.TBAAStruct);
   setMetadata(LLVMContext::MD_alias_scope, N.Scope);
-  setMetadata(LLVMContext::MD_noalias, N.NoAlias);
+  if (!N.NoAliasProvenance)
+    setMetadata(LLVMContext::MD_noalias, N.NoAlias);
+  // else postpone until setAAMetadataNoAliasProvenance
+}
+
+void Instruction::setAAMetadataNoAliasProvenance(const AAMDNodes &N) {
+  // It is not correct to always propagate the ptr_provenance.
+  // 'setAAMetadata' must already have been called !
+  if (N.NoAliasProvenance) {
+    // postponed from setAAMetadata
+    setMetadata(LLVMContext::MD_noalias, N.NoAlias);
+    if (LoadInst *LI = dyn_cast<LoadInst>(this)) {
+      LI->setNoaliasProvenanceOperand(N.NoAliasProvenance);
+    } else if (StoreInst *SI = dyn_cast<StoreInst>(this)) {
+      SI->setNoaliasProvenanceOperand(N.NoAliasProvenance);
+    }
+  }
 }
 
 MDNode *Instruction::getMetadataImpl(unsigned KindID) const {
Index: llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll
===================================================================
--- llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll
+++ llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll
@@ -52,4 +52,3 @@
 ; CHECK: NoAlias:   store float %1, float* %arrayidx.i2, align 4, !noalias !6 <->   store float %0, float* %arrayidx.i, align 4, !noalias !6
 ; CHECK: NoAlias:   store float %2, float* %arrayidx.i3, align 4, !noalias !7 <->   store float %0, float* %arrayidx.i, align 4, !noalias !6
 ; CHECK: NoAlias:   store float %2, float* %arrayidx.i3, align 4, !noalias !7 <->   store float %1, float* %arrayidx.i2, align 4, !noalias !6
-
Index: llvm/test/Analysis/ScopedNoAliasAA/basic2.ll
===================================================================
--- llvm/test/Analysis/ScopedNoAliasAA/basic2.ll
+++ llvm/test/Analysis/ScopedNoAliasAA/basic2.ll
@@ -38,4 +38,3 @@
 !3 = !{!3, !2, !"some other scope"}
 !4 = !{!1}
 !5 = !{!3}
-
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias-calls.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias-calls.ll
@@ -0,0 +1,62 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #1
+
+; Function Attrs: nounwind
+declare void @hey() #1
+
+; Function Attrs: nounwind uwtable
+define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 {
+entry:
+  %l.i = alloca i8, i32 512, align 1
+  %prov.a = call i8* @llvm.provenance.noalias.p0i8.p0i8.p0p0i8.p0p0i8.i32(i8* %a, i8* null, i8** null, i8** null, i32 0, metadata !0) #0
+  %prov.b = call i8* @llvm.provenance.noalias.p0i8.p0i8.p0p0i8.p0p0i8.i32(i8* %c, i8* null, i8** null, i8** null, i32 0, metadata !3) #0
+  %a.guard = call i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8* %a, i8* %prov.a)
+  %c.guard = call i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8* %c, i8* %prov.b)
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+  call void @hey() #1, !noalias !5
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+  ret void
+}
+
+; CHECK-LABEL: Function: foo:
+; CHECK: Just Ref:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: Just Mod:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: Just Ref:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <->   call void @hey() #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: Just Mod:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: Just Mod:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @hey() #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: Just Mod:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @hey() #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: Just Mod:   call void @hey() #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5
+; CHECK: Both ModRef:   call void @hey() #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @hey() #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @hey() #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %c.guard, i64 16, i1 false) #1, !noalias !5
+; CHECK: NoModRef:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %c.guard, i64 16, i1 false) #1, !noalias !5 <->   call void @hey() #1, !noalias !5
+
+declare i8* @llvm.provenance.noalias.p0i8.p0i8.p0p0i8.p0p0i8.i32(i8*, i8*, i8**, i8**, i32, metadata) nounwind readnone speculatable
+declare i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8*, i8*) nounwind readnone
+
+attributes #0 = { argmemonly nounwind }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind uwtable }
+
+
+!0 = !{!1}
+!1 = distinct !{!1, !2, !"hello: %a"}
+!2 = distinct !{!2, !"hello"}
+!3 = !{!4}
+!4 = distinct !{!4, !2, !"hello: %c"}
+!5 = !{!1, !4}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias-dup-scope.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias-dup-scope.ll
@@ -0,0 +1,161 @@
+; RUN: opt < %s -basic-aa -domtree -scoped-noalias-aa -aa-eval -loops -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s -check-prefix=WITHDT
+; Note: The -loops above can be anything that requires the domtree, and is
+; necessary to work around a pass-manager bug.
+
+target datalayout = "E-m:e-i64:64-n32:64"
+target triple = "powerpc64-unknown-linux-gnu"
+
+@a = common global i32* null, align 8
+@r = common global i32 0, align 4
+@a2 = common global i32* null, align 8
+
+; Function Attrs: nounwind
+define i32* @foo() #0 {
+entry:
+  %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5
+  %1 = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !5) #0
+  %2 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %0, i32* %1) #0
+  ret i32* %1
+}
+
+; Function Attrs: nounwind
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #0
+
+; Function Attrs: nounwind
+declare i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32*, i32*) #0
+
+; Function Attrs: nounwind
+define i32* @foo1(i32 signext %b) #0 {
+entry:
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %entry
+  %0 = load i32*, i32** @a, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !8
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !12) #0
+  %2 = load i32, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !13, !noalias !8
+  %3 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !8
+  %add = add nsw i32 %3, %2
+  store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !8
+  %guard.1 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %0, i32* %1) #0
+  tail call void @ex1(i32* %guard.1) #0, !noalias !8
+  %incdec.ptr = getelementptr inbounds i32, i32* %0, i64 1
+  %4 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !12) #0
+  %5 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !8
+  store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !13, !noalias !8
+  %guard.5 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %incdec.ptr, i32* %4) #0
+  tail call void @ex1(i32* %guard.5) #0, !noalias !8
+  %idx.ext = sext i32 %b to i64
+  %add.ptr = getelementptr inbounds i32, i32* %incdec.ptr, i64 %idx.ext
+  %6 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !12) #0
+  %7 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !8
+  store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !13, !noalias !8
+  %guard.6 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %add.ptr, i32* %6) #0
+  tail call void @ex1(i32* %guard.6) #0, !noalias !8
+  %8 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !8
+  %9 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %8, i8* null, i32** @a2, i32** null, i32 0, metadata !15) #0
+  %10 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !8
+  store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !13, !noalias !8
+  %guard.9 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %8, i32* %9) #0
+  tail call void @ex1(i32* %guard.9) #0, !noalias !8
+  br label %if.end
+
+if.else:                                          ; preds = %entry
+  %11 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !12
+  %12 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %11, i8* null, i32** @a2, i32** null, i32 0, metadata !12) #0
+  %13 = load i32, i32* %11, ptr_provenance i32* %12, align 4, !tbaa !13, !noalias !12
+  %14 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !12
+  %add1 = add nsw i32 %14, %13
+  store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !13, !noalias !12
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  %x.0 = phi i32* [ %0, %if.then ], [ %11, %if.else ]
+  %prov.x.0 = phi i32* [ %6, %if.then ], [ %12, %if.else ]
+  %x.0.guard = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %x.0, i32* %prov.x.0) #0
+  ret i32* %x.0.guard
+}
+
+; WITHDT:  NoAlias:   %0 = load i32*, i32** @a, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %0 = load i32*, i32** @a, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %0 = load i32*, i32** @a, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %0 = load i32*, i32** @a, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %0 = load i32*, i32** @a, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  NoAlias:   %2 = load i32, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %2 = load i32, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MayAlias:   %2 = load i32, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !10, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %2 = load i32, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !10, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %2 = load i32, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !10, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  MustAlias:   %3 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %3 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %3 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %3 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MustAlias:   %3 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  MustAlias:   %5 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %5 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %5 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %5 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MustAlias:   %5 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  MustAlias:   %7 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %7 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %7 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %7 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MustAlias:   %7 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  NoAlias:   %8 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %8 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %8 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %8 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %8 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  MustAlias:   %10 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %10 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %10 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %10 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MustAlias:   %10 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  NoAlias:   %11 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !9 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %11 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !9 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %11 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !9 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MayAlias:   %11 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !9 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %11 = load i32*, i32** @a2, ptr_provenance i32** null, align 8, !tbaa !1, !noalias !9 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  NoAlias:   %13 = load i32, i32* %11, ptr_provenance i32* %12, align 4, !tbaa !10, !noalias !9 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %13 = load i32, i32* %11, ptr_provenance i32* %12, align 4, !tbaa !10, !noalias !9 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %13 = load i32, i32* %11, ptr_provenance i32* %12, align 4, !tbaa !10, !noalias !9 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MayAlias:   %13 = load i32, i32* %11, ptr_provenance i32* %12, align 4, !tbaa !10, !noalias !9 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %13 = load i32, i32* %11, ptr_provenance i32* %12, align 4, !tbaa !10, !noalias !9 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  MustAlias:   %14 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %14 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   %14 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MayAlias:   %14 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MustAlias:   %14 = load i32, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9
+; WITHDT:  NoAlias:   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MustAlias:   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %add, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %5, i32* %incdec.ptr, ptr_provenance i32* %4, align 4, !tbaa !10, !noalias !5
+; WITHDT:  NoAlias:   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %7, i32* %add.ptr, ptr_provenance i32* %6, align 4, !tbaa !10, !noalias !5
+; WITHDT:  MayAlias:   store i32 %add1, i32* @r, ptr_provenance i32* null, align 4, !tbaa !10, !noalias !9 <->   store i32 %10, i32* %8, ptr_provenance i32* %9, align 4, !tbaa !10, !noalias !5
+
+declare void @ex1(i32*)
+
+attributes #0 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6}
+!6 = distinct !{!6, !7, !"foo: x"}
+!7 = distinct !{!7, !"foo"}
+!8 = !{!9, !11}
+!9 = distinct !{!9, !10, !"foo1: x2"}
+!10 = distinct !{!10, !"foo1"}
+!11 = distinct !{!11, !10, !"foo1: x"}
+!12 = !{!11}
+!13 = !{!14, !14, i64 0}
+!14 = !{!"int", !3, i64 0}
+!15 = !{!9}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias.ll
@@ -0,0 +1,66 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @foo(float* nocapture %a, float* nocapture readonly %c, i64 %i0, i64 %i1) #0 {
+entry:
+  %prov.a = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !0) #1
+  %0 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !0
+  %arrayidx.i = getelementptr inbounds float, float* %a, i64 %i0
+  store float %0, float* %arrayidx.i, ptr_provenance float* %prov.a, align 4, !noalias !0
+  %1 = load float, float* %c, align 4
+  %arrayidx = getelementptr inbounds float, float* %a, i64 %i1
+  store float %1, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !0
+  ret void
+}
+
+; CHECK-LABEL: Function: foo:
+; CHECK: NoAlias:   %0 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !0 <->   store float %0, float* %arrayidx.i, ptr_provenance float* %prov.a, align 4, !noalias !0
+; CHECK: MayAlias:   %0 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !0 <->   store float %1, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !0
+; CHECK: MayAlias:   %1 = load float, float* %c, align 4 <->   store float %0, float* %arrayidx.i, ptr_provenance float* %prov.a, align 4, !noalias !0
+; CHECK: MayAlias:   %1 = load float, float* %c, align 4 <->   store float %1, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !0
+; CHECK: NoAlias:   store float %1, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !0 <->   store float %0, float* %arrayidx.i, ptr_provenance float* %prov.a, align 4, !noalias !0
+
+
+; Function Attrs: nounwind uwtable
+define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c, i64 %i0, i64 %i1) #0 {
+entry:
+  %0 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !3) #1
+  %1 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %b, i8* null, float** null, float** null, i32 0, metadata !6) #1
+  %2 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !8
+  %arrayidx.i = getelementptr inbounds float, float* %a, i64 5
+  store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+  %arrayidx1.i = getelementptr inbounds float, float* %b, i64 %i0
+  store float %2, float* %arrayidx1.i, ptr_provenance float* %1, align 4, !noalias !8
+  %3 = load float, float* %c, align 4
+  %arrayidx = getelementptr inbounds float, float* %a, i64 %i1
+  store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !8
+  ret void
+}
+
+; CHECK-LABEL: Function: foo2:
+; CHECK: NoAlias:   %2 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !5 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+; CHECK: NoAlias:   %2 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !5 <->   store float %2, float* %arrayidx1.i, ptr_provenance float* %1, align 4, !noalias !5
+; CHECK: MayAlias:   %2 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !5 <->   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5
+; CHECK: MayAlias:   %3 = load float, float* %c, align 4 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+; CHECK: MayAlias:   %3 = load float, float* %c, align 4 <->   store float %2, float* %arrayidx1.i, ptr_provenance float* %1, align 4, !noalias !5
+; CHECK: MayAlias:   %3 = load float, float* %c, align 4 <->   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5
+; CHECK: NoAlias:   store float %2, float* %arrayidx1.i, ptr_provenance float* %1, align 4, !noalias !5 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+; CHECK: NoAlias:   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+; CHECK: NoAlias:   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5 <->   store float %2, float* %arrayidx1.i, ptr_provenance float* %1, align 4, !noalias !5
+
+declare float*  @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float*, i8*, float**, float**, i32, metadata ) nounwind
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind }
+
+!0 = !{!1}
+!1 = distinct !{!1, !2, !"hello: %a"}
+!2 = distinct !{!2, !"hello"}
+!3 = !{!4}
+!4 = distinct !{!4, !5, !"hello2: %a"}
+!5 = distinct !{!5, !"hello2"}
+!6 = !{!7}
+!7 = distinct !{!7, !5, !"hello2: %b"}
+!8 = !{!4, !7}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias2.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias2.ll
@@ -0,0 +1,113 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
+entry:
+  %0 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !0) #1
+  %1 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %c, i8* null, float** null, float** null, i32 0, metadata !3) #1
+  %2 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !5
+  %arrayidx.i = getelementptr inbounds float, float* %a, i64 5
+  store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+  %3 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !5
+  %arrayidx = getelementptr inbounds float, float* %a, i64 7
+  store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5
+  ret void
+}
+
+; CHECK-LABEL: Function: foo:
+; CHECK: NoAlias:   %2 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !5 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+; CHECK: NoAlias:   %2 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !5 <->   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5
+; CHECK: NoAlias:   %3 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !5 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+; CHECK: NoAlias:   %3 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !5 <->   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5
+; CHECK: NoAlias:   store float %3, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !5 <->   store float %2, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !5
+
+; Function Attrs: nounwind uwtable
+define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+entry:
+  %0 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !6) #1
+  %1 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %c, i8* null, float** null, float** null, i32 0, metadata !9) #1
+  %2 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %0, i8* null, float** null, float** null, i32 0, metadata !11) #1, !noalias !14
+  %3 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %1, i8* null, float** null, float** null, i32 0, metadata !15) #1, !noalias !14
+  %4 = load float, float* %c, ptr_provenance float* %3, align 4, !noalias !17
+  %arrayidx.i.i = getelementptr inbounds float, float* %a, i64 5
+  store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !17
+  %5 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !14
+  %arrayidx.i = getelementptr inbounds float, float* %a, i64 7
+  store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !14
+  %6 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !18) #1
+  %7 = call float* @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %b, i8* null, float** null, float** null, i32 0, metadata !21) #1
+  %8 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !23
+  %arrayidx.i1 = getelementptr inbounds float, float* %a, i64 6
+  store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !23
+  %arrayidx1.i = getelementptr inbounds float, float* %b, i64 8
+  store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !23
+  ; %9 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !23
+  %9 = load float, float* %c, align 4
+  %arrayidx = getelementptr inbounds float, float* %a, i64 7
+  store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !23
+  ret void
+}
+
+; CHECK-LABEL: Function: foo2:
+; CHECK: NoAlias:   %4 = load float, float* %c, ptr_provenance float* %3, align 4, !noalias !11 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: NoAlias:   %4 = load float, float* %c, ptr_provenance float* %3, align 4, !noalias !11 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: MayAlias:   %4 = load float, float* %c, ptr_provenance float* %3, align 4, !noalias !11 <->   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17
+; CHECK: MayAlias:   %4 = load float, float* %c, ptr_provenance float* %3, align 4, !noalias !11 <->   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17
+; CHECK: MayAlias:   %4 = load float, float* %c, ptr_provenance float* %3, align 4, !noalias !11 <->   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17
+; CHECK: NoAlias:   %5 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !8 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: NoAlias:   %5 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !8 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: MayAlias:   %5 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !8 <->   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17
+; CHECK: MayAlias:   %5 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !8 <->   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17
+; CHECK: MayAlias:   %5 = load float, float* %c, ptr_provenance float* %1, align 4, !noalias !8 <->   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17
+; CHECK: MayAlias:   %8 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !17 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: MayAlias:   %8 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !17 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: NoAlias:   %8 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !17 <->   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17
+; CHECK: NoAlias:   %8 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !17 <->   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17
+; CHECK: MayAlias:   %8 = load float, float* %c, ptr_provenance float* null, align 4, !noalias !17 <->   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17
+; CHECK: MayAlias:   %9 = load float, float* %c, align 4 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: MayAlias:   %9 = load float, float* %c, align 4 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: MayAlias:   %9 = load float, float* %c, align 4 <->   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17
+; CHECK: MayAlias:   %9 = load float, float* %c, align 4 <->   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17
+; CHECK: MayAlias:   %9 = load float, float* %c, align 4 <->   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17
+; CHECK: NoAlias:   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: NoAlias:   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: NoAlias:   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: MayAlias:   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: MayAlias:   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: NoAlias:   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17 <->   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17
+; CHECK: NoAlias:   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17 <->   store float %4, float* %arrayidx.i.i, ptr_provenance float* %2, align 4, !noalias !11
+; CHECK: MustAlias:   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17 <->   store float %5, float* %arrayidx.i, ptr_provenance float* %0, align 4, !noalias !8
+; CHECK: NoAlias:   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17 <->   store float %8, float* %arrayidx.i1, ptr_provenance float* %6, align 4, !noalias !17
+; CHECK: NoAlias:   store float %9, float* %arrayidx, ptr_provenance float* null, align 4, !noalias !17 <->   store float %8, float* %arrayidx1.i, ptr_provenance float* %7, align 4, !noalias !17
+
+declare float*  @llvm.provenance.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float*, i8*, float**, float**, i32, metadata ) nounwind
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind }
+
+!0 = !{!1}
+!1 = distinct !{!1, !2, !"hello: %a"}
+!2 = distinct !{!2, !"hello"}
+!3 = !{!4}
+!4 = distinct !{!4, !2, !"hello: %c"}
+!5 = !{!1, !4}
+!6 = !{!7}
+!7 = distinct !{!7, !8, !"foo: %a"}
+!8 = distinct !{!8, !"foo"}
+!9 = !{!10}
+!10 = distinct !{!10, !8, !"foo: %c"}
+!11 = !{!12}
+!12 = distinct !{!12, !13, !"hello: %a"}
+!13 = distinct !{!13, !"hello"}
+!14 = !{!7, !10}
+!15 = !{!16}
+!16 = distinct !{!16, !13, !"hello: %c"}
+!17 = !{!12, !16, !7, !10}
+!18 = !{!19}
+!19 = distinct !{!19, !20, !"hello2: %a"}
+!20 = distinct !{!20, !"hello2"}
+!21 = !{!22}
+!22 = distinct !{!22, !20, !"hello2: %b"}
+!23 = !{!19, !22}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_basics.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias_basics.ll
@@ -0,0 +1,142 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nofree norecurse nounwind uwtable writeonly
+define dso_local void @test_p_p(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #0 {
+entry:
+  store i32 42, i32* %_pA, align 4, !tbaa !2
+  store i32 99, i32* %_pB, align 4, !tbaa !2
+  ret void
+}
+; CHECK-LABEL: Function: test_p_p:
+; CHECK:   MayAlias:   store i32 99, i32* %_pB, align 4, !tbaa !2 <->   store i32 42, i32* %_pA, align 4, !tbaa !2
+
+; Function Attrs: nounwind uwtable
+define dso_local void @test_rp_p(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !6)
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !6), !tbaa !9, !noalias !6
+  store i32 42, i32* %_pA, ptr_provenance i32* %1, align 4, !tbaa !2, !noalias !6
+  store i32 99, i32* %_pB, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !6
+  ret void
+}
+; CHECK-LABEL: Function: test_rp_p:
+; CHECK:  NoAlias:   store i32 99, i32* %_pB, ptr_provenance i32* undef, align 4, !tbaa !9, !noalias !2 <->   store i32 42, i32* %_pA, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #2
+
+; Function Attrs: nounwind uwtable
+define dso_local void @test_rp_rp_00(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !11)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !14)
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !2, !noalias !16
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !14), !tbaa !9, !noalias !16
+  store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !16
+  ret void
+}
+; CHECK-LABEL: Function: test_rp_rp_00:
+; CHECK:  NoAlias:   store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !12, !noalias !11 <->   store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !12, !noalias !11
+
+; Now test variants: {objectP, objectID, Scope }
+; NOTE: in the following tests, the Scope information is recycled from previous tests
+
+; Same info -> MayAlias
+; Function Attrs: nounwind uwtable
+define dso_local void @test_rp_rp_01(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 {
+entry:
+  %a.p = alloca i32*, align 8
+  %b.p = alloca i32*, align 8
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11)
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !2, !noalias !16
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !16
+  ret void
+}
+; CHECK-LABEL: Function: test_rp_rp_01:
+; CHECK:  MayAlias:   store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !11, !noalias !9 <->   store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !11, !noalias !9
+
+; Variants with different info -> NoAlias
+
+; Function Attrs: nounwind uwtable
+define dso_local void @test_rp_rp_02(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 {
+entry:
+  %a.p = alloca i32*, align 8
+  %b.p = alloca i32*, align 8
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11)
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !2, !noalias !16
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %b.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !16
+  ret void
+}
+; CHECK-LABEL: Function: test_rp_rp_02:
+; CHECK:    NoAlias:   store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !11, !noalias !9 <->   store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !11, !noalias !9
+
+; Function Attrs: nounwind uwtable
+define dso_local void @test_rp_rp_03(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 {
+entry:
+  %a.p = alloca i32*, align 8
+  %b.p = alloca i32*, align 8
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11)
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !2, !noalias !16
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %a.p, i32** undef, i32 1, metadata !11), !tbaa !9, !noalias !16
+  store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !16
+  ret void
+}
+; CHECK-LABEL: Function: test_rp_rp_03:
+; CHECK:    NoAlias:   store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !11, !noalias !9 <->   store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !11, !noalias !9
+
+; Function Attrs: nounwind uwtable
+define dso_local void @test_rp_rp_04(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 {
+entry:
+  %a.p = alloca i32*, align 8
+  %b.p = alloca i32*, align 8
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11)
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16
+  store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !2, !noalias !16
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %a.p, i32** undef, i32 0, metadata !14), !tbaa !9, !noalias !16
+  store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !16
+  ret void
+}
+; CHECK-LABEL: Function: test_rp_rp_04:
+; CHECK:    NoAlias:   store i32 99, i32* %_pB, ptr_provenance i32* %3, align 4, !tbaa !11, !noalias !9 <->   store i32 42, i32* %_pA, ptr_provenance i32* %2, align 4, !tbaa !11, !noalias !9
+
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #3
+
+attributes #0 = { nofree norecurse nounwind uwtable writeonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { argmemonly nounwind }
+attributes #3 = { nounwind readnone speculatable }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang"}
+!2 = !{!3, !3, i64 0}
+!3 = !{!"int", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!7}
+!7 = distinct !{!7, !8, !"test_rp_p: pA"}
+!8 = distinct !{!8, !"test_rp_p"}
+!9 = !{!10, !10, i64 0}
+!10 = !{!"any pointer", !4, i64 0}
+!11 = !{!12}
+!12 = distinct !{!12, !13, !"test_rp_rp: pA"}
+!13 = distinct !{!13, !"test_rp_rp"}
+!14 = !{!15}
+!15 = distinct !{!15, !13, !"test_rp_rp: pB"}
+!16 = !{!12, !15}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_member.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias_member.ll
@@ -0,0 +1,64 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.FOO = type { i32*, i32* }
+
+; Function Attrs: nofree nounwind
+define dso_local void @test_prp0_prp1(i32** nocapture %_pA) local_unnamed_addr #0 !noalias !2 {
+entry:
+  %0 = load i32*, i32** %_pA, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** %_pA, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2
+  %arrayidx1 = getelementptr inbounds i32*, i32** %_pA, i32 1
+  %2 = load i32*, i32** %arrayidx1, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %2, i8* null, i32** nonnull %arrayidx1, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2
+  store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+  store i32 99, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !9, !noalias !2
+  ret void
+}
+; CHECK-LABEL: Function: test_prp0_prp1:
+; CHECK:  NoAlias:   store i32 99, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !9, !noalias !2 <->   store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+
+; Function Attrs: nofree nounwind
+define dso_local void @test_prS0_prS1(%struct.FOO* nocapture %_pS) local_unnamed_addr #0 !noalias !11 {
+entry:
+  %mpA = getelementptr inbounds %struct.FOO, %struct.FOO* %_pS, i32 0, i32 0
+  %0 = load i32*, i32** %mpA, ptr_provenance i32** undef, align 4, !tbaa !14, !noalias !11
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** %mpA, i32** undef, i32 0, metadata !11), !tbaa !14, !noalias !11
+  %mpB = getelementptr inbounds %struct.FOO, %struct.FOO* %_pS, i32 0, i32 1
+  %2 = load i32*, i32** %mpB, ptr_provenance i32** undef, align 4, !tbaa !16, !noalias !11
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %2, i8* null, i32** nonnull %mpB, i32** undef, i32 0, metadata !11), !tbaa !16, !noalias !11
+  store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !11
+  store i32 99, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !9, !noalias !11
+  ret void
+}
+; CHECK-LABEL: Function: test_prS0_prS1:
+; CHECK:  NoAlias:   store i32 99, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !11, !noalias !2 <->   store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !11, !noalias !2
+
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #1
+
+attributes #0 = { nofree nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang"}
+!2 = !{!3}
+!3 = distinct !{!3, !4, !"test_prp0_prp1: unknown scope"}
+!4 = distinct !{!4, !"test_prp0_prp1"}
+!5 = !{!6, !6, i64 0, i64 4}
+!6 = !{!7, i64 4, !"any pointer"}
+!7 = !{!8, i64 1, !"omnipotent char"}
+!8 = !{!"Simple C/C++ TBAA"}
+!9 = !{!10, !10, i64 0, i64 4}
+!10 = !{!7, i64 4, !"int"}
+!11 = !{!12}
+!12 = distinct !{!12, !13, !"test_prS0_prS1: unknown scope"}
+!13 = distinct !{!13, !"test_prS0_prS1"}
+!14 = !{!15, !6, i64 0, i64 4}
+!15 = !{!7, i64 8, !"FOO", !6, i64 0, i64 4, !6, i64 4, i64 4}
+!16 = !{!15, !6, i64 4, i64 4}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_phi.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias_phi.ll
@@ -0,0 +1,230 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nofree norecurse nounwind writeonly
+define dso_local void @test_phi_p_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #0 {
+entry:
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !2
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2
+  ret void
+}
+; CHECK-LABEL: Function: test_phi_p_p_p:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2 <->   store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !2
+
+; Function Attrs: nounwind
+define dso_local void @test_phi_rp_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !6)
+  %tobool = icmp ne i32 %c, 0
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !6)
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ]
+  %prov.cond = phi i32* [ %1, %cond.true ], [ %_pB, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !6
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !6
+  ret void
+}
+; CHECK-LABEL: Function: test_phi_rp_p_p:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !5, !noalias !2 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !5, !noalias !2
+
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #2
+
+; Function Attrs: nounwind
+define dso_local void @test_phi_p_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !9)
+  %tobool = icmp ne i32 %c, 0
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %0, i32** null, i32** undef, i32 0, metadata !9)
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ]
+  %prov.cond = phi i32* [ %_pA, %cond.true ], [ %1, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !9
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !9
+  ret void
+}
+; CHECK-LABEL: Function: test_phi_p_rp_p:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !5, !noalias !2 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !5, !noalias !2
+
+; Function Attrs: nounwind
+define dso_local void @test_phi_rp_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !12)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !15)
+  %tobool = icmp ne i32 %c, 0
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !12)
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !15)
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ]
+  %prov.cond = phi i32* [ %2, %cond.true ], [ %3, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !17
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !17
+  ret void
+}
+; CHECK-LABEL: Function: test_phi_rp_rp_p:
+; CHECK:  NoAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !7, !noalias !11 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !7, !noalias !11
+
+; Function Attrs: nounwind
+define dso_local void @test_phi_p_p_rp(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !18)
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !18
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %0, i32** null, i32** undef, i32 0, metadata !18), !tbaa !21, !noalias !18
+  store i32 99, i32* %_pC, ptr_provenance i32* %1, align 4, !tbaa !2, !noalias !18
+  ret void
+}
+; CHECK-LABEL: Function: test_phi_p_p_rp:
+; CHECK:  NoAlias:   store i32 99, i32* %_pC, ptr_provenance i32* %1, align 4, !tbaa !5, !noalias !2 <->   store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !5, !noalias !2
+
+; Function Attrs: nounwind
+define dso_local void @test_phi_rp_rp_rp_01(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !23)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !26)
+  %2 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !28)
+  %tobool = icmp ne i32 %c, 0
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !23)
+  %4 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !26)
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ]
+  %prov.cond = phi i32* [ %3, %cond.true ], [ %4, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !30
+  %5 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %2, i32** null, i32** undef, i32 0, metadata !28), !tbaa !21, !noalias !30
+  store i32 99, i32* %_pC, ptr_provenance i32* %5, align 4, !tbaa !2, !noalias !30
+  ret void
+}
+
+; CHECK-LABEL: Function: test_phi_rp_rp_rp_01:
+; CHECK:  NoAlias:   store i32 99, i32* %_pC, ptr_provenance i32* %5, align 4, !tbaa !9, !noalias !13 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !9, !noalias !13
+
+; Function Attrs: nounwind
+define dso_local void @test_phi_rp_rp_rp_02(i32* nocapture %_pA, i32* nocapture readnone %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !31)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !34)
+  %tobool = icmp ne i32 %c, 0
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !31)
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %1, i32** null, i32** undef, i32 0, metadata !34)
+  br i1 %tobool, label %cond.false, label %cond.true
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i32* [ %_pA, %cond.true ], [ %_pC, %cond.false ]
+  %prov.cond = phi i32* [ %2, %cond.true ], [ %3, %cond.false ]
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !36
+  store i32 99, i32* %_pC, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !36
+  ret void
+}
+; CHECK-LABEL: Function: test_phi_rp_rp_rp_02:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* %3, align 4, !tbaa !7, !noalias !11 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !7, !noalias !11
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #3
+
+attributes #0 = { nofree norecurse nounwind writeonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { argmemonly nounwind }
+attributes #3 = { nounwind readnone speculatable }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang"}
+!2 = !{!3, !3, i64 0, i64 4}
+!3 = !{!4, i64 4, !"int"}
+!4 = !{!5, i64 1, !"omnipotent char"}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!7}
+!7 = distinct !{!7, !8, !"test_phi_rp_p_p: pA"}
+!8 = distinct !{!8, !"test_phi_rp_p_p"}
+!9 = !{!10}
+!10 = distinct !{!10, !11, !"test_phi_p_rp_p: pB"}
+!11 = distinct !{!11, !"test_phi_p_rp_p"}
+!12 = !{!13}
+!13 = distinct !{!13, !14, !"test_phi_rp_rp_p: pA"}
+!14 = distinct !{!14, !"test_phi_rp_rp_p"}
+!15 = !{!16}
+!16 = distinct !{!16, !14, !"test_phi_rp_rp_p: pB"}
+!17 = !{!13, !16}
+!18 = !{!19}
+!19 = distinct !{!19, !20, !"test_phi_p_p_rp: pC"}
+!20 = distinct !{!20, !"test_phi_p_p_rp"}
+!21 = !{!22, !22, i64 0, i64 4}
+!22 = !{!4, i64 4, !"any pointer"}
+!23 = !{!24}
+!24 = distinct !{!24, !25, !"test_phi_rp_rp_rp_01: pA"}
+!25 = distinct !{!25, !"test_phi_rp_rp_rp_01"}
+!26 = !{!27}
+!27 = distinct !{!27, !25, !"test_phi_rp_rp_rp_01: pB"}
+!28 = !{!29}
+!29 = distinct !{!29, !25, !"test_phi_rp_rp_rp_01: pC"}
+!30 = !{!24, !27, !29}
+!31 = !{!32}
+!32 = distinct !{!32, !33, !"test_phi_rp_rp_rp_02: pA"}
+!33 = distinct !{!33, !"test_phi_rp_rp_rp_02"}
+!34 = !{!35}
+!35 = distinct !{!35, !33, !"test_phi_rp_rp_rp_02: pC"}
+!36 = !{!32, !37, !35}
+!37 = distinct !{!37, !33, !"test_phi_rp_rp_rp_02: pB"}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_phi_in_loop.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias_phi_in_loop.ll
@@ -0,0 +1,154 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind
+define dso_local void @test_complex_phi_01(i32* nocapture %_pA, i32** nocapture readonly %_pB, i32 %n) local_unnamed_addr #0 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !2)
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2
+  %2 = load i32*, i32** %_pB, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx1 = getelementptr inbounds i32*, i32** %_pB, i32 1
+  %3 = load i32*, i32** %arrayidx1, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx2 = getelementptr inbounds i32*, i32** %_pB, i32 2
+  %4 = load i32*, i32** %arrayidx2, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx3 = getelementptr inbounds i32*, i32** %_pB, i32 3
+  %5 = load i32*, i32** %arrayidx3, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx4 = getelementptr inbounds i32*, i32** %_pB, i32 4
+  %6 = load i32*, i32** %arrayidx4, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx5 = getelementptr inbounds i32*, i32** %_pB, i32 5
+  %7 = load i32*, i32** %arrayidx5, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx6 = getelementptr inbounds i32*, i32** %_pB, i32 6
+  %8 = load i32*, i32** %arrayidx6, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx7 = getelementptr inbounds i32*, i32** %_pB, i32 7
+  %9 = load i32*, i32** %arrayidx7, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx8 = getelementptr inbounds i32*, i32** %_pB, i32 8
+  %10 = load i32*, i32** %arrayidx8, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx9 = getelementptr inbounds i32*, i32** %_pB, i32 9
+  %11 = load i32*, i32** %arrayidx9, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %prov.pTmp00.0 = phi i32* [ %2, %entry ], [ %prov.pTmp01.0, %for.cond ]
+  %pTmp00.0 = phi i32* [ %2, %entry ], [ %pTmp01.0, %for.cond ]
+  %prov.pTmp01.0 = phi i32* [ %3, %entry ], [ %prov.pTmp02.0, %for.cond ]
+  %pTmp01.0 = phi i32* [ %3, %entry ], [ %pTmp02.0, %for.cond ]
+  %prov.pTmp02.0 = phi i32* [ %4, %entry ], [ %prov.pTmp03.0, %for.cond ]
+  %pTmp02.0 = phi i32* [ %4, %entry ], [ %pTmp03.0, %for.cond ]
+  %prov.pTmp03.0 = phi i32* [ %5, %entry ], [ %prov.pTmp04.0, %for.cond ]
+  %pTmp03.0 = phi i32* [ %5, %entry ], [ %pTmp04.0, %for.cond ]
+  %prov.pTmp04.0 = phi i32* [ %6, %entry ], [ %prov.pTmp05.0, %for.cond ]
+  %pTmp04.0 = phi i32* [ %6, %entry ], [ %pTmp05.0, %for.cond ]
+  %prov.pTmp05.0 = phi i32* [ %7, %entry ], [ %prov.pTmp06.0, %for.cond ]
+  %pTmp05.0 = phi i32* [ %7, %entry ], [ %pTmp06.0, %for.cond ]
+  %prov.pTmp06.0 = phi i32* [ %8, %entry ], [ %prov.pTmp07.0, %for.cond ]
+  %pTmp06.0 = phi i32* [ %8, %entry ], [ %pTmp07.0, %for.cond ]
+  %prov.pTmp07.0 = phi i32* [ %9, %entry ], [ %prov.pTmp08.0, %for.cond ]
+  %pTmp07.0 = phi i32* [ %9, %entry ], [ %pTmp08.0, %for.cond ]
+  %prov.pTmp08.0 = phi i32* [ %10, %entry ], [ %prov.pTmp09.0, %for.cond ]
+  %pTmp08.0 = phi i32* [ %10, %entry ], [ %pTmp09.0, %for.cond ]
+  %prov.pTmp09.0 = phi i32* [ %11, %entry ], [ %1, %for.cond ]
+  %pTmp09.0 = phi i32* [ %11, %entry ], [ %_pA, %for.cond ]
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
+  %cmp = icmp slt i32 %i.0, %n
+  %inc = add nuw nsw i32 %i.0, 1
+  br i1 %cmp, label %for.cond, label %for.cond.cleanup
+
+for.cond.cleanup:                                 ; preds = %for.cond
+  store i32 99, i32* %_pA, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+  store i32 42, i32* %pTmp00.0, ptr_provenance i32* %prov.pTmp00.0, align 4, !tbaa !9, !noalias !2
+  ret void
+}
+
+; CHECK-LABEL: Function: test_complex_phi_01:
+; CHECK:  MayAlias:   store i32 42, i32* %pTmp00.0, ptr_provenance i32* %prov.pTmp00.0, align 4, !tbaa !9, !noalias !2 <->   store i32 99, i32* %_pA, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+
+
+; Adapted version where the ptr_provenance chains don't collapse
+; Function Attrs: nounwind
+define dso_local void @test_complex_phi_02(i32* nocapture %_pA, i32** nocapture readonly %_pB, i32 %n) local_unnamed_addr #0 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !2)
+  %decl2 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 1, metadata !2)
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2
+  %extra_ptr = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %decl2, i32** null, i32** undef, i32 1, metadata !2), !tbaa !5, !noalias !2
+  %2 = load i32*, i32** %_pB, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx1 = getelementptr inbounds i32*, i32** %_pB, i32 1
+  %3 = load i32*, i32** %arrayidx1, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx2 = getelementptr inbounds i32*, i32** %_pB, i32 2
+  %4 = load i32*, i32** %arrayidx2, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx3 = getelementptr inbounds i32*, i32** %_pB, i32 3
+  %5 = load i32*, i32** %arrayidx3, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx4 = getelementptr inbounds i32*, i32** %_pB, i32 4
+  %6 = load i32*, i32** %arrayidx4, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx5 = getelementptr inbounds i32*, i32** %_pB, i32 5
+  %7 = load i32*, i32** %arrayidx5, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx6 = getelementptr inbounds i32*, i32** %_pB, i32 6
+  %8 = load i32*, i32** %arrayidx6, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx7 = getelementptr inbounds i32*, i32** %_pB, i32 7
+  %9 = load i32*, i32** %arrayidx7, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx8 = getelementptr inbounds i32*, i32** %_pB, i32 8
+  %10 = load i32*, i32** %arrayidx8, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  %arrayidx9 = getelementptr inbounds i32*, i32** %_pB, i32 9
+  %11 = load i32*, i32** %arrayidx9, ptr_provenance i32** undef, align 4, !tbaa !5, !noalias !2
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %prov.pTmp00.0 = phi i32* [ %2, %entry ], [ %prov.pTmp01.0, %for.cond ]
+  %pTmp00.0 = phi i32* [ %2, %entry ], [ %pTmp01.0, %for.cond ]
+  %prov.pTmp01.0 = phi i32* [ %3, %entry ], [ %prov.pTmp02.0, %for.cond ]
+  %pTmp01.0 = phi i32* [ %3, %entry ], [ %pTmp02.0, %for.cond ]
+  %prov.pTmp02.0 = phi i32* [ %4, %entry ], [ %prov.pTmp03.0, %for.cond ]
+  %pTmp02.0 = phi i32* [ %4, %entry ], [ %pTmp03.0, %for.cond ]
+  %prov.pTmp03.0 = phi i32* [ %5, %entry ], [ %prov.pTmp04.0, %for.cond ]
+  %pTmp03.0 = phi i32* [ %5, %entry ], [ %pTmp04.0, %for.cond ]
+  %prov.pTmp04.0 = phi i32* [ %6, %entry ], [ %prov.pTmp05.0, %for.cond ]
+  %pTmp04.0 = phi i32* [ %6, %entry ], [ %pTmp05.0, %for.cond ]
+  %prov.pTmp05.0 = phi i32* [ %7, %entry ], [ %prov.pTmp06.0, %for.cond ]
+  %pTmp05.0 = phi i32* [ %7, %entry ], [ %pTmp06.0, %for.cond ]
+  %prov.pTmp06.0 = phi i32* [ %8, %entry ], [ %prov.pTmp07.0, %for.cond ]
+  %pTmp06.0 = phi i32* [ %8, %entry ], [ %pTmp07.0, %for.cond ]
+  %prov.pTmp07.0 = phi i32* [ %9, %entry ], [ %prov.pTmp08.0, %for.cond ]
+  %pTmp07.0 = phi i32* [ %9, %entry ], [ %pTmp08.0, %for.cond ]
+  %prov.pTmp08.0 = phi i32* [ %10, %entry ], [ %prov.pTmp09.0, %for.cond ]
+  %pTmp08.0 = phi i32* [ %10, %entry ], [ %pTmp09.0, %for.cond ]
+  %prov.pTmp09.0 = phi i32* [ %11, %entry ], [ %extra_ptr, %for.cond ]
+  %pTmp09.0 = phi i32* [ %11, %entry ], [ %_pA, %for.cond ]
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
+  %cmp = icmp slt i32 %i.0, %n
+  %inc = add nuw nsw i32 %i.0, 1
+  br i1 %cmp, label %for.cond, label %for.cond.cleanup
+
+for.cond.cleanup:                                 ; preds = %for.cond
+  store i32 99, i32* %_pA, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+  store i32 42, i32* %pTmp00.0, ptr_provenance i32* %prov.pTmp00.0, align 4, !tbaa !9, !noalias !2
+  ret void
+}
+
+; CHECK-LABEL: Function: test_complex_phi_02:
+; CHECK:  NoAlias:   store i32 42, i32* %pTmp00.0, ptr_provenance i32* %prov.pTmp00.0, align 4, !tbaa !9, !noalias !2 <->   store i32 99, i32* %_pA, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone speculatable }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang"}
+!2 = !{!3}
+!3 = distinct !{!3, !4, !"test_complex_phi: rpTmp"}
+!4 = distinct !{!4, !"test_complex_phi"}
+!5 = !{!6, !6, i64 0, i64 4}
+!6 = !{!7, i64 4, !"any pointer"}
+!7 = !{!8, i64 1, !"omnipotent char"}
+!8 = !{!"Simple C/C++ TBAA"}
+!9 = !{!10, !10, i64 0, i64 4}
+!10 = !{!7, i64 4, !"int"}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_recursive.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias_recursive.ll
@@ -0,0 +1,127 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=basic-aa,scoped-noalias-aa -passes=aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind
+define dso_local void @test_prp_prp(i32** nocapture readonly %_pA, i32** nocapture readonly %_pB) local_unnamed_addr #0 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !2)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !5)
+  %2 = tail call i32** @llvm.provenance.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pA, i8* %0, i32*** null, i32*** undef, i64 0, metadata !2), !tbaa !7, !noalias !11
+  %3 = load i32*, i32** %_pA, ptr_provenance i32** %2, align 4, !tbaa !7, !noalias !11
+  store i32 42, i32* %3, ptr_provenance i32* undef, align 4, !tbaa !12, !noalias !11
+  %4 = tail call i32** @llvm.provenance.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pB, i8* %1, i32*** null, i32*** undef, i64 0, metadata !5), !tbaa !7, !noalias !11
+  %5 = load i32*, i32** %_pB, ptr_provenance i32** %4, align 4, !tbaa !7, !noalias !11
+  store i32 99, i32* %5, ptr_provenance i32* undef, align 4, !tbaa !12, !noalias !11
+  ret void
+}
+; CHECK-LABEL: Function: test_prp_prp:
+; CHECK:  MayAlias:   store i32 99, i32* %5, ptr_provenance i32* undef, align 4, !tbaa !12, !noalias !11 <->   store i32 42, i32* %3, ptr_provenance i32* undef, align 4, !tbaa !12, !noalias !11
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32***, i64, metadata) #1
+
+; Function Attrs: nofree nounwind
+define dso_local void @test_rpp_rpp(i32** nocapture %_pA, i32** nocapture %_pB) local_unnamed_addr #2 !noalias !14 {
+entry:
+  %0 = load i32*, i32** %_pA, ptr_provenance i32** undef, align 4, !tbaa !7, !noalias !14
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %_pA, i32** undef, i64 0, metadata !14), !tbaa !7, !noalias !14
+  store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !12, !noalias !14
+  %2 = load i32*, i32** %_pB, ptr_provenance i32** undef, align 4, !tbaa !7, !noalias !14
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %2, i8* null, i32** %_pB, i32** undef, i64 0, metadata !14), !tbaa !7, !noalias !14
+  store i32 99, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !12, !noalias !14
+  ret void
+}
+; CHECK-LABEL: Function: test_rpp_rpp:
+; CHECK:  MayAlias:   store i32 99, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !9, !noalias !2 <->   store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+
+; Function Attrs: nounwind
+define dso_local void @test_rprp_rprp(i32** nocapture %_pA, i32** nocapture %_pB) local_unnamed_addr #0 !noalias !17 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !20)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !22)
+  %2 = tail call i32** @llvm.provenance.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pA, i8* %0, i32*** null, i32*** undef, i64 0, metadata !20), !tbaa !7, !noalias !24
+  %3 = load i32*, i32** %_pA, ptr_provenance i32** %2, align 4, !tbaa !7, !noalias !24
+  %4 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %3, i8* null, i32** %_pA, i32** %2, i64 0, metadata !17), !tbaa !7, !noalias !24
+  store i32 42, i32* %3, ptr_provenance i32* %4, align 4, !tbaa !12, !noalias !24
+  %5 = tail call i32** @llvm.provenance.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pB, i8* %1, i32*** null, i32*** undef, i64 0, metadata !22), !tbaa !7, !noalias !24
+  %6 = load i32*, i32** %_pB, ptr_provenance i32** %5, align 4, !tbaa !7, !noalias !24
+  %7 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %6, i8* null, i32** %_pB, i32** %5, i64 0, metadata !17), !tbaa !7, !noalias !24
+  store i32 99, i32* %6, ptr_provenance i32* %7, align 4, !tbaa !12, !noalias !24
+  ret void
+}
+
+; CHECK-LABEL: Function: test_rprp_rprp:
+; CHECK:  NoAlias:   store i32 99, i32* %6, ptr_provenance i32* %7, align 4, !tbaa !14, !noalias !13 <->   store i32 42, i32* %3, ptr_provenance i32* %4, align 4, !tbaa !14, !noalias !13
+
+; Function Attrs: nounwind
+define dso_local void @test_prp_01(i32** nocapture %pA) local_unnamed_addr #0 !noalias !17 {
+entry:
+  %0 = load i32*, i32** %pA, ptr_provenance i32** undef, align 8, !tbaa !7, !noalias !17
+  %1 = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pA, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17
+  store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !12, !noalias !17
+  %arrayidx1 = getelementptr inbounds i32*, i32** %pA, i64 0
+  %2 = load i32*, i32** %arrayidx1, ptr_provenance i32** undef, align 8, !tbaa !7, !noalias !17
+  %3 = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %2, i8* null, i32** %arrayidx1, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17
+  store i32 43, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !12, !noalias !17
+  ret void
+}
+
+; CHECK-LABEL: Function: test_prp_01:
+; CHECK:  MayAlias: store i32 43, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+; Function Attrs: nounwind
+define dso_local void @test_prp_02(i32** nocapture %pA) local_unnamed_addr #0 !noalias !17 {
+entry:
+  %0 = load i32*, i32** %pA, ptr_provenance i32** undef, align 8, !tbaa !7, !noalias !17
+  %1 = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pA, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17
+  store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !12, !noalias !17
+  %arrayidx1 = getelementptr inbounds i32*, i32** %pA, i64 1
+  %2 = load i32*, i32** %arrayidx1, ptr_provenance i32** undef, align 8, !tbaa !7, !noalias !17
+  %3 = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %2, i8* null, i32** %arrayidx1, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17
+  store i32 43, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !12, !noalias !17
+  ret void
+}
+
+; CHECK-LABEL: Function: test_prp_02:
+; CHECK:  NoAlias: store i32 43, i32* %2, ptr_provenance i32* %3, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %0, ptr_provenance i32* %1, align 4, !tbaa !9, !noalias !2
+
+; Function Attrs: nounwind readnone speculatable
+declare i32** @llvm.provenance.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32**, i8*, i32***, i32***, i64, metadata) #3
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32*, i8*, i32**, i32**, i64, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { nofree nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone speculatable }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang"}
+!2 = !{!3}
+!3 = distinct !{!3, !4, !"test_prp_prp: pA"}
+!4 = distinct !{!4, !"test_prp_prp"}
+!5 = !{!6}
+!6 = distinct !{!6, !4, !"test_prp_prp: pB"}
+!7 = !{!8, !8, i64 0, i64 4}
+!8 = !{!9, i64 4, !"any pointer"}
+!9 = !{!10, i64 1, !"omnipotent char"}
+!10 = !{!"Simple C/C++ TBAA"}
+!11 = !{!3, !6}
+!12 = !{!13, !13, i64 0, i64 4}
+!13 = !{!9, i64 4, !"int"}
+!14 = !{!15}
+!15 = distinct !{!15, !16, !"test_rpp_rpp: unknown scope"}
+!16 = distinct !{!16, !"test_rpp_rpp"}
+!17 = !{!18}
+!18 = distinct !{!18, !19, !"test_rprp_rprp: unknown scope"}
+!19 = distinct !{!19, !"test_rprp_rprp"}
+!20 = !{!21}
+!21 = distinct !{!21, !19, !"test_rprp_rprp: pA"}
+!22 = !{!23}
+!23 = distinct !{!23, !19, !"test_rprp_rprp: pB"}
+!24 = !{!21, !23, !18}
Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_select.ll
===================================================================
--- /dev/null
+++ llvm/test/Analysis/ScopedNoAliasAA/noalias_select.ll
@@ -0,0 +1,167 @@
+; RUN: opt < %s -basic-aa -scoped-noalias-aa -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nofree norecurse nounwind writeonly
+define dso_local void @test_select_p_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #0 {
+entry:
+  %tobool = icmp eq i32 %c, 0
+  %cond = select i1 %tobool, i32* %_pB, i32* %_pA
+  store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !2
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2
+  ret void
+}
+; CHECK-LABEL: Function: test_select_p_p_p:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2 <->   store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !2
+
+; Function Attrs: nounwind
+define dso_local void @test_select_rp_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !6)
+  %tobool = icmp ne i32 %c, 0
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !6)
+  %prov.cond = select i1 %tobool, i32* %1, i32* %_pB
+  %cond = select i1 %tobool, i32* %_pA, i32* %_pB
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !6
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !6
+  ret void
+}
+; CHECK-LABEL: Function: test_select_rp_p_p:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !5, !noalias !2 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !5, !noalias !2
+
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #2
+
+; Function Attrs: nounwind
+define dso_local void @test_select_p_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !9)
+  %tobool = icmp ne i32 %c, 0
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %0, i32** null, i32** undef, i32 0, metadata !9)
+  %prov.cond = select i1 %tobool, i32* %_pA, i32* %1
+  %cond = select i1 %tobool, i32* %_pA, i32* %_pB
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !9
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !9
+  ret void
+}
+; CHECK-LABEL: Function: test_select_p_rp_p:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !5, !noalias !2 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !5, !noalias !2
+
+; Function Attrs: nounwind
+define dso_local void @test_select_rp_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !12)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !15)
+  %tobool = icmp ne i32 %c, 0
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !12)
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !15)
+  %prov.cond = select i1 %tobool, i32* %2, i32* %3
+  %cond = select i1 %tobool, i32* %_pA, i32* %_pB
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !17
+  store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !17
+  ret void
+}
+; CHECK-LABEL: Function: test_select_rp_rp_p:
+; CHECK:  NoAlias:   store i32 99, i32* %_pC, ptr_provenance i32* undef, align 4, !tbaa !7, !noalias !11 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !7, !noalias !11
+
+; Function Attrs: nounwind
+define dso_local void @test_select_p_p_rp(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !18)
+  %tobool = icmp eq i32 %c, 0
+  %cond = select i1 %tobool, i32* %_pB, i32* %_pA
+  store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !2, !noalias !18
+  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %0, i32** null, i32** undef, i32 0, metadata !18), !tbaa !21, !noalias !18
+  store i32 99, i32* %_pC, ptr_provenance i32* %1, align 4, !tbaa !2, !noalias !18
+  ret void
+}
+; CHECK-LABEL: Function: test_select_p_p_rp:
+; CHECK:  NoAlias:   store i32 99, i32* %_pC, ptr_provenance i32* %1, align 4, !tbaa !5, !noalias !2 <->   store i32 42, i32* %cond, ptr_provenance i32* undef, align 4, !tbaa !5, !noalias !2
+
+; Function Attrs: nounwind
+define dso_local void @test_select_rp_rp_rp_01(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !23)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !26)
+  %2 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !28)
+  %tobool = icmp ne i32 %c, 0
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !23)
+  %4 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !26)
+  %prov.cond = select i1 %tobool, i32* %3, i32* %4
+  %cond = select i1 %tobool, i32* %_pA, i32* %_pB
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !30
+  %5 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %2, i32** null, i32** undef, i32 0, metadata !28), !tbaa !21, !noalias !30
+  store i32 99, i32* %_pC, ptr_provenance i32* %5, align 4, !tbaa !2, !noalias !30
+  ret void
+}
+
+; CHECK-LABEL: Function: test_select_rp_rp_rp_01:
+; CHECK:  NoAlias:   store i32 99, i32* %_pC, ptr_provenance i32* %5, align 4, !tbaa !9, !noalias !13 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !9, !noalias !13
+
+; Function Attrs: nounwind
+define dso_local void @test_select_rp_rp_rp_02(i32* nocapture %_pA, i32* nocapture readnone %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 {
+entry:
+  %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !31)
+  %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !34)
+  %tobool = icmp ne i32 %c, 0
+  %2 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !31)
+  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %1, i32** null, i32** undef, i32 0, metadata !34)
+  %prov.cond = select i1 %tobool, i32* %2, i32* %3
+  %cond = select i1 %tobool, i32* %_pA, i32* %_pC
+  store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !2, !noalias !36
+  store i32 99, i32* %_pC, ptr_provenance i32* %3, align 4, !tbaa !2, !noalias !36
+  ret void
+}
+; CHECK-LABEL: Function: test_select_rp_rp_rp_02:
+; CHECK:  MayAlias:   store i32 99, i32* %_pC, ptr_provenance i32* %3, align 4, !tbaa !7, !noalias !11 <->   store i32 42, i32* %cond, ptr_provenance i32* %prov.cond, align 4, !tbaa !7, !noalias !11
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #3
+
+attributes #0 = { nofree norecurse nounwind writeonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { argmemonly nounwind }
+attributes #3 = { nounwind readnone speculatable }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang"}
+!2 = !{!3, !3, i64 0, i64 4}
+!3 = !{!4, i64 4, !"int"}
+!4 = !{!5, i64 1, !"omnipotent char"}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!7}
+!7 = distinct !{!7, !8, !"test_select_rp_p_p: pA"}
+!8 = distinct !{!8, !"test_select_rp_p_p"}
+!9 = !{!10}
+!10 = distinct !{!10, !11, !"test_select_p_rp_p: pB"}
+!11 = distinct !{!11, !"test_select_p_rp_p"}
+!12 = !{!13}
+!13 = distinct !{!13, !14, !"test_select_rp_rp_p: pA"}
+!14 = distinct !{!14, !"test_select_rp_rp_p"}
+!15 = !{!16}
+!16 = distinct !{!16, !14, !"test_select_rp_rp_p: pB"}
+!17 = !{!13, !16}
+!18 = !{!19}
+!19 = distinct !{!19, !20, !"test_select_p_p_rp: pC"}
+!20 = distinct !{!20, !"test_select_p_p_rp"}
+!21 = !{!22, !22, i64 0, i64 4}
+!22 = !{!4, i64 4, !"any pointer"}
+!23 = !{!24}
+!24 = distinct !{!24, !25, !"test_select_rp_rp_rp_01: pA"}
+!25 = distinct !{!25, !"test_select_rp_rp_rp_01"}
+!26 = !{!27}
+!27 = distinct !{!27, !25, !"test_select_rp_rp_rp_01: pB"}
+!28 = !{!29}
+!29 = distinct !{!29, !25, !"test_select_rp_rp_rp_01: pC"}
+!30 = !{!24, !27, !29}
+!31 = !{!32}
+!32 = distinct !{!32, !33, !"test_select_rp_rp_rp_02: pA"}
+!33 = distinct !{!33, !"test_select_rp_rp_rp_02"}
+!34 = !{!35}
+!35 = distinct !{!35, !33, !"test_select_rp_rp_rp_02: pC"}
+!36 = !{!32, !37, !35}
+!37 = distinct !{!37, !33, !"test_select_rp_rp_rp_02: pB"}