4 byte gap between the two fields. This gap represents padding which
does not carry useful data and need not be preserved.
+'``noalias``' and '``alias.scope``' Metadata
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``noalias`` and ``alias.scope`` metadata provide the ability to specify generic
+noalias memory-access sets. This means that some collection of memory access
+instructions (loads, stores, memory-accessing calls, etc.) that carry
+``noalias`` metadata can specifically be specified not to alias with some other
+collection of memory access instructions that carry ``alias.scope`` metadata.
+Each type of metadata specifies a list of scopes, and when evaluating an
+aliasing query, if one of the instructions has a scope in its ``alias.scope``
+list that is identical to a scope in the other instruction's ``noalias`` list,
+or is a descendant (in the scope hierarchy) of a scope in the other
+instruction's ``noalias`` list , then the two memory accesses are assumed not
+to alias.
+
+The metadata identifying each scope is itself a list containing one or two
+entries. The first entry is the name of the scope. Note that if the name is a
+string then it can be combined accross functions and translation units. A
+self-reference can be used to create globally unique scope names.
+Optionally, a metadata reference to a parent scope can be provided as a second
+entry in the list.
+
+For example,
+
+.. code-block:: llvm
+
+ ; A root scope (which doubles as a list of itself):
+ !0 = metadata !{metadata !0}
+
+ ; Two child scopes (which must be self-referential to avoid being "uniqued"):
+ !1 = metadata !{metadata !2} ; A list containing only scope !2
+ !2 = metadata !{metadata !2, metadata !0} ; Scope !2 is a descendant of scope !0
+
+ !3 = metadata !{metadata !4} ; A list containing only scope !4
+ !4 = metadata !{metadata !4, metadata !0} ; Scope !4 is a descendant of scope !0
+
+ ; These two instructions don't alias:
+ %0 = load float* %c, align 4, !alias.scope !0
+ store float %0, float* %arrayidx.i, align 4, !noalias !0
+
+ ; These two instructions may alias (scope !2 and scope !4 are peers):
+ %2 = load float* %c, align 4, !alias.scope !1
+ store float %2, float* %arrayidx.i2, align 4, !noalias !3
+
+ ; These two instructions don't alias (scope !2 is a descendant of scope !0
+ ; and the store does not alias with anything in scope !0 or any of its descendants):
+ %2 = load float* %c, align 4, !alias.scope !1
+ store float %0, float* %arrayidx.i, align 4, !noalias !0
+
+ ; These two instructions may alias:
+ %2 = load float* %c, align 4, !alias.scope !0
+ store float %0, float* %arrayidx.i, align 4, !noalias !1
+
'``fpmath``' Metadata
^^^^^^^^^^^^^^^^^^^^^
/** See llvm::createTypeBasedAliasAnalysisPass function */
void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM);
+/** See llvm::createScopedNoAliasAAPass function */
+void LLVMAddScopedNoAliasAAPass(LLVMPassManagerRef PM);
+
/** See llvm::createBasicAliasAnalysisPass function */
void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);
//===--------------------------------------------------------------------===//
//
+ // createScopedNoAliasAAPass - This pass implements metadata-based
+ // scoped noalias analysis.
+ //
+ ImmutablePass *createScopedNoAliasAAPass();
+
+ //===--------------------------------------------------------------------===//
+ //
// createObjCARCAliasAnalysisPass - This pass implements ObjC-ARC-based
// alias analysis.
//
/// \brief Create and insert a memset to the specified pointer and the
/// specified value.
///
- /// If the pointer isn't an i8*, it will be converted. If a TBAA tag is
- /// specified, it will be added to the instruction.
+ /// If the pointer isn't an i8*, it will be converted. If a TBAA tag is
+ /// specified, it will be added to the instruction. Likewise with alias.scope
+ /// and noalias tags.
CallInst *CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, unsigned Align,
- bool isVolatile = false, MDNode *TBAATag = nullptr) {
- return CreateMemSet(Ptr, Val, getInt64(Size), Align, isVolatile, TBAATag);
+ bool isVolatile = false, MDNode *TBAATag = nullptr,
+ MDNode *ScopeTag = nullptr,
+ MDNode *NoAliasTag = nullptr) {
+ return CreateMemSet(Ptr, Val, getInt64(Size), Align, isVolatile,
+ TBAATag, ScopeTag, NoAliasTag);
}
CallInst *CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align,
- bool isVolatile = false, MDNode *TBAATag = nullptr);
+ bool isVolatile = false, MDNode *TBAATag = nullptr,
+ MDNode *ScopeTag = nullptr,
+ MDNode *NoAliasTag = nullptr);
/// \brief Create and insert a memcpy between the specified pointers.
///
/// If the pointers aren't i8*, they will be converted. If a TBAA tag is
- /// specified, it will be added to the instruction.
+ /// specified, it will be added to the instruction. Likewise with alias.scope
+ /// and noalias tags.
CallInst *CreateMemCpy(Value *Dst, Value *Src, uint64_t Size, unsigned Align,
bool isVolatile = false, MDNode *TBAATag = nullptr,
- MDNode *TBAAStructTag = nullptr) {
+ MDNode *TBAAStructTag = nullptr,
+ MDNode *ScopeTag = nullptr,
+ MDNode *NoAliasTag = nullptr) {
return CreateMemCpy(Dst, Src, getInt64(Size), Align, isVolatile, TBAATag,
- TBAAStructTag);
+ TBAAStructTag, ScopeTag, NoAliasTag);
}
CallInst *CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align,
bool isVolatile = false, MDNode *TBAATag = nullptr,
- MDNode *TBAAStructTag = nullptr);
+ MDNode *TBAAStructTag = nullptr,
+ MDNode *ScopeTag = nullptr,
+ MDNode *NoAliasTag = nullptr);
/// \brief Create and insert a memmove between the specified
/// pointers.
///
/// If the pointers aren't i8*, they will be converted. If a TBAA tag is
- /// specified, it will be added to the instruction.
+ /// specified, it will be added to the instruction. Likewise with alias.scope
+ /// and noalias tags.
CallInst *CreateMemMove(Value *Dst, Value *Src, uint64_t Size, unsigned Align,
- bool isVolatile = false, MDNode *TBAATag = nullptr) {
- return CreateMemMove(Dst, Src, getInt64(Size), Align, isVolatile, TBAATag);
+ bool isVolatile = false, MDNode *TBAATag = nullptr,
+ MDNode *ScopeTag = nullptr,
+ MDNode *NoAliasTag = nullptr) {
+ return CreateMemMove(Dst, Src, getInt64(Size), Align, isVolatile,
+ TBAATag, ScopeTag, NoAliasTag);
}
CallInst *CreateMemMove(Value *Dst, Value *Src, Value *Size, unsigned Align,
- bool isVolatile = false, MDNode *TBAATag = nullptr);
+ bool isVolatile = false, MDNode *TBAATag = nullptr,
+ MDNode *ScopeTag = nullptr,
+ MDNode *NoAliasTag = nullptr);
/// \brief Create a lifetime.start intrinsic.
///
MD_fpmath = 3, // "fpmath"
MD_range = 4, // "range"
MD_tbaa_struct = 5, // "tbaa.struct"
- MD_invariant_load = 6 // "invariant.load"
+ MD_invariant_load = 6, // "invariant.load"
+ MD_alias_scope = 7, // "alias.scope"
+ MD_noalias = 8 // "noalias"
};
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
MDNode *createRange(const APInt &Lo, const APInt &Hi);
//===------------------------------------------------------------------===//
- // TBAA metadata.
+ // AA metadata.
//===------------------------------------------------------------------===//
- /// \brief Return metadata appropriate for a TBAA root node. Each returned
+protected:
+ /// \brief Return metadata appropriate for a AA root node (scope or TBAA).
+ /// Each returned node is distinct from all other metadata and will never
+ /// be identified (uniqued) with anything else.
+ MDNode *createAnonymousAARoot(StringRef Name = StringRef());
+
+public:
+ /// \brief Return metadata appropriate for a TBAA root node. Each returned
/// node is distinct from all other metadata and will never be identified
/// (uniqued) with anything else.
- MDNode *createAnonymousTBAARoot();
+ MDNode *createAnonymousTBAARoot() {
+ return createAnonymousAARoot();
+ }
+
+ /// \brief Return metadata appropriate for an alias scope root node.
+ /// Each returned node is distinct from all other metadata and will never
+ /// be identified (uniqued) with anything else.
+ MDNode *createAnonymousAliasScopeRoot(StringRef Name = StringRef()) {
+ return createAnonymousAARoot(Name);
+ }
/// \brief Return metadata appropriate for a TBAA root node with the given
/// name. This may be identified (uniqued) with other roots with the same
/// name.
MDNode *createTBAARoot(StringRef Name);
+ /// \brief Return metadata appropriate for an alias scope root node with
+ /// the given name. This may be identified (uniqued) with other roots with
+ /// the same name.
+ MDNode *createAliasScopeRoot(StringRef Name);
+
/// \brief Return metadata for a non-root TBAA node with the given name,
/// parent in the TBAA tree, and value for 'pointsToConstantMemory'.
MDNode *createTBAANode(StringRef Name, MDNode *Parent,
bool isConstant = false);
+ /// \brief Return metadata for a non-root alias scope node with the given
+ /// name and parent in the scope tree.
+ MDNode *createAliasScopeNode(StringRef Name, MDNode *Parent);
+
struct TBAAStructField {
uint64_t Offset;
uint64_t Size;
/// AAMDNodes - A collection of metadata nodes that might be associated with a
/// memory access used by the alias-analysis infrastructure.
struct AAMDNodes {
- AAMDNodes(MDNode *T = nullptr)
- : TBAA(T) {}
+ AAMDNodes(MDNode *T = nullptr, MDNode *S = nullptr, MDNode *N = nullptr)
+ : TBAA(T), Scope(S), NoAlias(N) {}
bool operator == (const AAMDNodes &A) const {
return equals(A);
}
operator bool() const {
- return TBAA;
+ return TBAA || Scope || NoAlias;
}
/// TBAA - The tag for type-based alias analysis.
MDNode *TBAA;
+ /// Scope - The tag for alias scope specification (used with noalias).
+ MDNode *Scope;
+
+ /// NoAlias - The tag specifying the noalias scope.
+ MDNode *NoAlias;
+
protected:
bool equals(const AAMDNodes &A) const {
- return TBAA == A.TBAA;
+ return TBAA == A.TBAA && Scope == A.Scope && NoAlias == A.NoAlias;
}
};
template<>
struct DenseMapInfo<AAMDNodes> {
static inline AAMDNodes getEmptyKey() {
- return AAMDNodes(DenseMapInfo<MDNode *>::getEmptyKey());
+ return AAMDNodes(DenseMapInfo<MDNode *>::getEmptyKey(), 0, 0);
}
static inline AAMDNodes getTombstoneKey() {
- return AAMDNodes(DenseMapInfo<MDNode *>::getTombstoneKey());
+ return AAMDNodes(DenseMapInfo<MDNode *>::getTombstoneKey(), 0, 0);
}
static unsigned getHashValue(const AAMDNodes &Val) {
- return DenseMapInfo<MDNode *>::getHashValue(Val.TBAA);
+ return DenseMapInfo<MDNode *>::getHashValue(Val.TBAA) ^
+ DenseMapInfo<MDNode *>::getHashValue(Val.Scope) ^
+ DenseMapInfo<MDNode *>::getHashValue(Val.NoAlias);
}
static bool isEqual(const AAMDNodes &LHS, const AAMDNodes &RHS) {
return LHS == RHS;
bool isTBAAVtableAccess() const;
/// Methods for metadata merging.
+ static MDNode *concatenate(MDNode *A, MDNode *B);
+ static MDNode *intersect(MDNode *A, MDNode *B);
static MDNode *getMostGenericTBAA(MDNode *A, MDNode *B);
static AAMDNodes getMostGenericAA(const AAMDNodes &A, const AAMDNodes &B);
static MDNode *getMostGenericFPMath(MDNode *A, MDNode *B);
void initializeTargetLibraryInfoPass(PassRegistry&);
void initializeTwoAddressInstructionPassPass(PassRegistry&);
void initializeTypeBasedAliasAnalysisPass(PassRegistry&);
+void initializeScopedNoAliasAAPass(PassRegistry&);
void initializeUnifyFunctionExitNodesPass(PassRegistry&);
void initializeUnreachableBlockElimPass(PassRegistry&);
void initializeUnreachableMachineBlockElimPass(PassRegistry&);
(void) llvm::createLibCallAliasAnalysisPass(nullptr);
(void) llvm::createScalarEvolutionAliasAnalysisPass();
(void) llvm::createTypeBasedAliasAnalysisPass();
+ (void) llvm::createScopedNoAliasAAPass();
(void) llvm::createBoundsCheckingPass();
(void) llvm::createBreakCriticalEdgesPass();
(void) llvm::createCallGraphPrinterPass();
initializeScalarEvolutionAliasAnalysisPass(Registry);
initializeTargetTransformInfoAnalysisGroup(Registry);
initializeTypeBasedAliasAnalysisPass(Registry);
+ initializeScopedNoAliasAAPass(Registry);
}
void LLVMInitializeAnalysis(LLVMPassRegistryRef R) {
TargetTransformInfo.cpp
Trace.cpp
TypeBasedAliasAnalysis.cpp
+ ScopedNoAliasAA.cpp
ValueTracking.cpp
)
--- /dev/null
+//===- ScopedNoAliasAA.cpp - Scoped No-Alias Alias Analysis ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ScopedNoAlias alias-analysis pass, which implements
+// metadata-based scoped no-alias support.
+//
+// Alias-analysis scopes are defined similar to TBAA nodes:
+//
+// !scope0 = metadata !{ metadata !"scope of foo()" }
+// !scope1 = metadata !{ metadata !"scope 1", metadata !scope0 }
+// !scope2 = metadata !{ metadata !"scope 2", metadata !scope0 }
+// !scope3 = metadata !{ metadata !"scope 2.1", metadata !scope2 }
+// !scope4 = metadata !{ metadata !"scope 2.2", metadata !scope2 }
+//
+// Loads and stores can be tagged with an alias-analysis scope, and also, with
+// a noalias tag for a specific scope:
+//
+// ... = load %ptr1, !alias.scope !{ !scope1 }
+// ... = load %ptr2, !alias.scope !{ !scope1, !scope2 }, !noalias !{ !scope1 }
+//
+// When evaluating an aliasing query, if one of the instructions is associated
+// with an alias.scope id that is identical to the noalias scope associated
+// with the other instruction, or is a descendant (in the scope hierarchy) of
+// the noalias scope associated with the other instruction, then the two memory
+// accesses are assumed not to alias.
+//
+// Note that if the first element of the scope metadata is a string, then it
+// can be combined accross functions and translation units. The string can be
+// replaced by a self-reference to create globally unqiue scope identifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/Passes.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+using namespace llvm;
+
+// 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));
+
+namespace {
+/// AliasScopeNode - This is a simple wrapper around an MDNode which provides
+/// a higher-level interface by hiding the details of how alias analysis
+/// information is encoded in its operands.
+class AliasScopeNode {
+ const MDNode *Node;
+
+public:
+ AliasScopeNode() : Node(0) {}
+ explicit AliasScopeNode(const MDNode *N) : Node(N) {}
+
+ /// getNode - Get the MDNode for this AliasScopeNode.
+ const MDNode *getNode() const { return Node; }
+
+ /// getParent - Get this AliasScopeNode's Alias tree parent.
+ AliasScopeNode getParent() const {
+ if (Node->getNumOperands() < 2)
+ return AliasScopeNode();
+ MDNode *P = dyn_cast_or_null<MDNode>(Node->getOperand(1));
+ if (!P)
+ return AliasScopeNode();
+ // Ok, this node has a valid parent. Return it.
+ return AliasScopeNode(P);
+ }
+};
+
+/// ScopedNoAliasAA - This is a simple alias analysis
+/// implementation that uses scoped-noalias metadata to answer queries.
+class ScopedNoAliasAA : public ImmutablePass, public AliasAnalysis {
+public:
+ static char ID; // Class identification, replacement for typeinfo
+ ScopedNoAliasAA() : ImmutablePass(ID) {
+ initializeScopedNoAliasAAPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual void initializePass() {
+ InitializeAliasAnalysis(this);
+ }
+
+ /// getAdjustedAnalysisPointer - This method is used when a pass implements
+ /// an analysis interface through multiple inheritance. If needed, it
+ /// should override this to adjust the this pointer as needed for the
+ /// specified pass info.
+ virtual void *getAdjustedAnalysisPointer(const void *PI) {
+ if (PI == &AliasAnalysis::ID)
+ return (AliasAnalysis*)this;
+ return this;
+ }
+
+protected:
+ bool mayAlias(const MDNode *A, const MDNode *B) const;
+ bool mayAliasInScopes(const MDNode *Scopes, const MDNode *NoAlias) const;
+
+private:
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const;
+ virtual AliasResult alias(const Location &LocA, const Location &LocB);
+ virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal);
+ virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS);
+ virtual ModRefBehavior getModRefBehavior(const Function *F);
+ virtual ModRefResult getModRefInfo(ImmutableCallSite CS,
+ const Location &Loc);
+ virtual ModRefResult getModRefInfo(ImmutableCallSite CS1,
+ ImmutableCallSite CS2);
+};
+} // End of anonymous namespace
+
+// Register this pass...
+char ScopedNoAliasAA::ID = 0;
+INITIALIZE_AG_PASS(ScopedNoAliasAA, AliasAnalysis, "scoped-noalias",
+ "Scoped NoAlias Alias Analysis", false, true, false)
+
+ImmutablePass *llvm::createScopedNoAliasAAPass() {
+ return new ScopedNoAliasAA();
+}
+
+void
+ScopedNoAliasAA::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.setPreservesAll();
+ AliasAnalysis::getAnalysisUsage(AU);
+}
+
+/// mayAlias - Test whether the scope represented by A may alias the
+/// scope represented by B. Specifically, A is the target scope, and B is the
+/// noalias scope.
+bool
+ScopedNoAliasAA::mayAlias(const MDNode *A,
+ const MDNode *B) const {
+ // Climb the tree from A to see if we reach B.
+ for (AliasScopeNode T(A); ; ) {
+ if (T.getNode() == B)
+ // B is an ancestor of A.
+ return false;
+
+ T = T.getParent();
+ if (!T.getNode())
+ break;
+ }
+
+ return true;
+}
+
+bool
+ScopedNoAliasAA::mayAliasInScopes(const MDNode *Scopes,
+ const MDNode *NoAlias) const {
+ if (!Scopes || !NoAlias)
+ return true;
+
+ for (unsigned i = 0, ie = Scopes->getNumOperands(); i != ie; ++i)
+ if (const MDNode *SMD = dyn_cast<MDNode>(Scopes->getOperand(i)))
+ for (unsigned j = 0, je = NoAlias->getNumOperands(); j != je; ++j)
+ if (const MDNode *NAMD = dyn_cast<MDNode>(NoAlias->getOperand(j)))
+ if (!mayAlias(SMD, NAMD))
+ return false;
+
+ return true;
+}
+
+AliasAnalysis::AliasResult
+ScopedNoAliasAA::alias(const Location &LocA, const Location &LocB) {
+ if (!EnableScopedNoAlias)
+ return AliasAnalysis::alias(LocA, LocB);
+
+ // Get the attached MDNodes.
+ const MDNode *AScopes = LocA.AATags.Scope,
+ *BScopes = LocB.AATags.Scope;
+
+ const MDNode *ANoAlias = LocA.AATags.NoAlias,
+ *BNoAlias = LocB.AATags.NoAlias;
+
+ if (!mayAliasInScopes(AScopes, BNoAlias))
+ return NoAlias;
+
+ if (!mayAliasInScopes(BScopes, ANoAlias))
+ return NoAlias;
+
+ // If they may alias, chain to the next AliasAnalysis.
+ return AliasAnalysis::alias(LocA, LocB);
+}
+
+bool ScopedNoAliasAA::pointsToConstantMemory(const Location &Loc,
+ bool OrLocal) {
+ return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal);
+}
+
+AliasAnalysis::ModRefBehavior
+ScopedNoAliasAA::getModRefBehavior(ImmutableCallSite CS) {
+ return AliasAnalysis::getModRefBehavior(CS);
+}
+
+AliasAnalysis::ModRefBehavior
+ScopedNoAliasAA::getModRefBehavior(const Function *F) {
+ return AliasAnalysis::getModRefBehavior(F);
+}
+
+AliasAnalysis::ModRefResult
+ScopedNoAliasAA::getModRefInfo(ImmutableCallSite CS, const Location &Loc) {
+ if (!EnableScopedNoAlias)
+ return AliasAnalysis::getModRefInfo(CS, Loc);
+
+ if (!mayAliasInScopes(Loc.AATags.Scope,
+ CS.getInstruction()->getMetadata(LLVMContext::MD_noalias)))
+ return NoModRef;
+
+ if (!mayAliasInScopes(
+ CS.getInstruction()->getMetadata(LLVMContext::MD_alias_scope),
+ Loc.AATags.NoAlias))
+ return NoModRef;
+
+ return AliasAnalysis::getModRefInfo(CS, Loc);
+}
+
+AliasAnalysis::ModRefResult
+ScopedNoAliasAA::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) {
+ if (!EnableScopedNoAlias)
+ return AliasAnalysis::getModRefInfo(CS1, CS2);
+
+ if (!mayAliasInScopes(
+ CS1.getInstruction()->getMetadata(LLVMContext::MD_alias_scope),
+ CS2.getInstruction()->getMetadata(LLVMContext::MD_noalias)))
+ return NoModRef;
+
+ if (!mayAliasInScopes(
+ CS2.getInstruction()->getMetadata(LLVMContext::MD_alias_scope),
+ CS1.getInstruction()->getMetadata(LLVMContext::MD_noalias)))
+ return NoModRef;
+
+ return AliasAnalysis::getModRefInfo(CS1, CS2);
+}
+
getMetadata(LLVMContext::MD_tbaa));
else
N.TBAA = getMetadata(LLVMContext::MD_tbaa);
+
+ if (Merge)
+ N.Scope = MDNode::intersect(N.Scope,
+ getMetadata(LLVMContext::MD_alias_scope));
+ else
+ N.Scope = getMetadata(LLVMContext::MD_alias_scope);
+
+ if (Merge)
+ N.NoAlias = MDNode::intersect(N.NoAlias,
+ getMetadata(LLVMContext::MD_noalias));
+ else
+ N.NoAlias = getMetadata(LLVMContext::MD_noalias);
}
OS << ")";
}
+ // Print AA scope info.
+ if (const MDNode *ScopeInfo = MMO.getAAInfo().Scope) {
+ OS << "(alias.scope=";
+ if (ScopeInfo->getNumOperands() > 0)
+ for (unsigned i = 0, ie = ScopeInfo->getNumOperands(); i != ie; ++i) {
+ ScopeInfo->getOperand(i)->printAsOperand(OS, /*PrintType=*/false);
+ if (i != ie-1)
+ OS << ",";
+ }
+ else
+ OS << "<unknown>";
+ OS << ")";
+ }
+
+ // Print AA noalias scope info.
+ if (const MDNode *NoAliasInfo = MMO.getAAInfo().NoAlias) {
+ OS << "(noalias=";
+ if (NoAliasInfo->getNumOperands() > 0)
+ for (unsigned i = 0, ie = NoAliasInfo->getNumOperands(); i != ie; ++i) {
+ NoAliasInfo->getOperand(i)->printAsOperand(OS, /*PrintType=*/false);
+ if (i != ie-1)
+ OS << ",";
+ }
+ else
+ OS << "<unknown>";
+ OS << ")";
+ }
+
// Print nontemporal info.
if (MMO.isNonTemporal())
OS << "(nontemporal)";
// BasicAliasAnalysis wins if they disagree. This is intended to help
// support "obvious" type-punning idioms.
addPass(createTypeBasedAliasAnalysisPass());
+ addPass(createScopedNoAliasAAPass());
addPass(createBasicAliasAnalysisPass());
// Before running any passes, run the verifier to determine if the input
CallInst *IRBuilderBase::
CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align,
- bool isVolatile, MDNode *TBAATag) {
+ bool isVolatile, MDNode *TBAATag, MDNode *ScopeTag,
+ MDNode *NoAliasTag) {
Ptr = getCastedInt8PtrValue(Ptr);
Value *Ops[] = { Ptr, Val, Size, getInt32(Align), getInt1(isVolatile) };
Type *Tys[] = { Ptr->getType(), Size->getType() };
// Set the TBAA info if present.
if (TBAATag)
CI->setMetadata(LLVMContext::MD_tbaa, TBAATag);
-
+
+ if (ScopeTag)
+ CI->setMetadata(LLVMContext::MD_alias_scope, ScopeTag);
+
+ if (NoAliasTag)
+ CI->setMetadata(LLVMContext::MD_noalias, NoAliasTag);
+
return CI;
}
CallInst *IRBuilderBase::
CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align,
- bool isVolatile, MDNode *TBAATag, MDNode *TBAAStructTag) {
+ bool isVolatile, MDNode *TBAATag, MDNode *TBAAStructTag,
+ MDNode *ScopeTag, MDNode *NoAliasTag) {
Dst = getCastedInt8PtrValue(Dst);
Src = getCastedInt8PtrValue(Src);
// Set the TBAA Struct info if present.
if (TBAAStructTag)
CI->setMetadata(LLVMContext::MD_tbaa_struct, TBAAStructTag);
-
+
+ if (ScopeTag)
+ CI->setMetadata(LLVMContext::MD_alias_scope, ScopeTag);
+
+ if (NoAliasTag)
+ CI->setMetadata(LLVMContext::MD_noalias, NoAliasTag);
+
return CI;
}
CallInst *IRBuilderBase::
CreateMemMove(Value *Dst, Value *Src, Value *Size, unsigned Align,
- bool isVolatile, MDNode *TBAATag) {
+ bool isVolatile, MDNode *TBAATag, MDNode *ScopeTag,
+ MDNode *NoAliasTag) {
Dst = getCastedInt8PtrValue(Dst);
Src = getCastedInt8PtrValue(Src);
// Set the TBAA info if present.
if (TBAATag)
CI->setMetadata(LLVMContext::MD_tbaa, TBAATag);
-
+
+ if (ScopeTag)
+ CI->setMetadata(LLVMContext::MD_alias_scope, ScopeTag);
+
+ if (NoAliasTag)
+ CI->setMetadata(LLVMContext::MD_noalias, NoAliasTag);
+
return CI;
}
unsigned InvariantLdId = getMDKindID("invariant.load");
assert(InvariantLdId == MD_invariant_load && "invariant.load kind id drifted");
(void)InvariantLdId;
+
+ // Create the 'alias.scope' metadata kind.
+ unsigned AliasScopeID = getMDKindID("alias.scope");
+ assert(AliasScopeID == MD_alias_scope && "alias.scope kind id drifted");
+ (void)AliasScopeID;
+
+ // Create the 'noalias' metadata kind.
+ unsigned NoAliasID = getMDKindID("noalias");
+ assert(NoAliasID == MD_noalias && "noalias kind id drifted");
+ (void)NoAliasID;
}
LLVMContext::~LLVMContext() { delete pImpl; }
return MDNode::get(Context, Range);
}
-MDNode *MDBuilder::createAnonymousTBAARoot() {
+MDNode *MDBuilder::createAnonymousAARoot(StringRef Name) {
// To ensure uniqueness the root node is self-referential.
- MDNode *Dummy = MDNode::getTemporary(Context, ArrayRef<Value *>());
- MDNode *Root = MDNode::get(Context, Dummy);
+ MDNode *Dummy = MDNode::getTemporary(Context, ArrayRef<Value*>());
+
+ SmallVector<Value *, 2> Args(1, Dummy);
+ if (!Name.empty())
+ Args.push_back(createString(Name));
+ MDNode *Root = MDNode::get(Context, Args);
+
// At this point we have
// !0 = metadata !{} <- dummy
// !1 = metadata !{metadata !0} <- root
}
}
+MDNode *MDBuilder::createAliasScopeRoot(StringRef Name) {
+ return MDNode::get(Context, createString(Name));
+}
+
+MDNode *MDBuilder::createAliasScopeNode(StringRef Name, MDNode *Parent) {
+ Value *Ops[2] = { createString(Name), Parent };
+ return MDNode::get(Context, Ops);
+}
+
/// \brief Return metadata for a tbaa.struct node with the given
/// struct field descriptions.
MDNode *MDBuilder::createTBAAStructNode(ArrayRef<TBAAStructField> Fields) {
}
}
+MDNode *MDNode::concatenate(MDNode *A, MDNode *B) {
+ if (!A)
+ return B;
+ if (!B)
+ return A;
+
+ SmallVector<Value *, 4> Vals(A->getNumOperands() +
+ B->getNumOperands());
+
+ unsigned j = 0;
+ for (unsigned i = 0, ie = A->getNumOperands(); i != ie; ++i)
+ Vals[j++] = A->getOperand(i);
+ for (unsigned i = 0, ie = B->getNumOperands(); i != ie; ++i)
+ Vals[j++] = B->getOperand(i);
+
+ return MDNode::get(A->getContext(), Vals);
+}
+
+MDNode *MDNode::intersect(MDNode *A, MDNode *B) {
+ if (!A || !B)
+ return nullptr;
+
+ SmallVector<Value *, 4> Vals;
+ for (unsigned i = 0, ie = A->getNumOperands(); i != ie; ++i) {
+ Value *V = A->getOperand(i);
+ for (unsigned j = 0, je = B->getNumOperands(); j != je; ++j)
+ if (V == B->getOperand(j)) {
+ Vals.push_back(V);
+ break;
+ }
+ }
+
+ return MDNode::get(A->getContext(), Vals);
+}
+
MDNode *MDNode::getMostGenericFPMath(MDNode *A, MDNode *B) {
if (!A || !B)
return nullptr;
void Instruction::setAAMetadata(const AAMDNodes &N) {
setMetadata(LLVMContext::MD_tbaa, N.TBAA);
+ setMetadata(LLVMContext::MD_alias_scope, N.Scope);
+ setMetadata(LLVMContext::MD_noalias, N.NoAlias);
}
MDNode *Instruction::getMetadataImpl(unsigned KindID) const {
// BasicAliasAnalysis wins if they disagree. This is intended to help
// support "obvious" type-punning idioms.
PM.add(createTypeBasedAliasAnalysisPass());
+ PM.add(createScopedNoAliasAAPass());
PM.add(createBasicAliasAnalysisPass());
}
case LLVMContext::MD_tbaa:
ReplInst->setMetadata(Kind, MDNode::getMostGenericTBAA(IMD, ReplMD));
break;
+ case LLVMContext::MD_alias_scope:
+ case LLVMContext::MD_noalias:
+ // FIXME: If both the original and replacement value are part of the
+ // same control-flow region (meaning that the execution of one
+ // guarentees the executation of the other), then we can combine the
+ // noalias scopes here and do better than the general conservative
+ // answer.
+
+ // In general, GVN unifies expressions over different control-flow
+ // regions, and so we need a conservative combination of the noalias
+ // scopes.
+ ReplInst->setMetadata(Kind, MDNode::intersect(IMD, ReplMD));
+ break;
case LLVMContext::MD_range:
ReplInst->setMetadata(Kind, MDNode::getMostGenericRange(IMD, ReplMD));
break;
unwrap(PM)->add(createTypeBasedAliasAnalysisPass());
}
+void LLVMAddScopedNoAliasAAPass(LLVMPassManagerRef PM) {
+ unwrap(PM)->add(createScopedNoAliasAAPass());
+}
+
void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM) {
unwrap(PM)->add(createBasicAliasAnalysisPass());
}
|| Tag == LLVMContext::MD_fpmath
|| Tag == LLVMContext::MD_tbaa_struct
|| Tag == LLVMContext::MD_invariant_load
+ || Tag == LLVMContext::MD_alias_scope
+ || Tag == LLVMContext::MD_noalias
|| Tag == ParallelLoopAccessMDKind);
}
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;
InvokeDest->removePredecessor(II->getParent());
}
+/// CloneAliasScopeMetadata - When inlining a function that contains noalias
+/// scope metadata, this metadata needs to be cloned so that the inlined blocks
+/// have different "unqiue scopes" at every call site. Were this not done, then
+/// aliasing scopes from a function inlined into a caller multiple times could
+/// not be differentiated (and this would lead to miscompiles because the
+/// non-aliasing property communicated by the metadata could have
+/// call-site-specific control dependencies).
+static void CloneAliasScopeMetadata(CallSite CS, ValueToValueMapTy &VMap) {
+ const Function *CalledFunc = CS.getCalledFunction();
+ SetVector<const MDNode *> MD;
+
+ // Note: We could only clone the metadata if it is already used in the
+ // caller. I'm omitting that check here because it might confuse
+ // inter-procedural alias analysis passes. We can revisit this if it becomes
+ // an efficiency or overhead problem.
+
+ for (Function::const_iterator I = CalledFunc->begin(), IE = CalledFunc->end();
+ I != IE; ++I)
+ for (BasicBlock::const_iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
+ if (const MDNode *M = J->getMetadata(LLVMContext::MD_alias_scope))
+ MD.insert(M);
+ if (const MDNode *M = J->getMetadata(LLVMContext::MD_noalias))
+ MD.insert(M);
+ }
+
+ if (MD.empty())
+ return;
+
+ // Walk the existing metadata, adding the complete (perhaps cyclic) chain to
+ // the set.
+ SmallVector<const Value *, 16> Queue(MD.begin(), MD.end());
+ while (!Queue.empty()) {
+ const MDNode *M = cast<MDNode>(Queue.pop_back_val());
+ for (unsigned i = 0, ie = M->getNumOperands(); i != ie; ++i)
+ if (const MDNode *M1 = dyn_cast<MDNode>(M->getOperand(i)))
+ if (MD.insert(M1))
+ Queue.push_back(M1);
+ }
+
+ // Now we have a complete set of all metadata in the chains used to specify
+ // the noalias scopes and the lists of those scopes.
+ SmallVector<MDNode *, 16> DummyNodes;
+ DenseMap<const MDNode *, TrackingVH<MDNode> > MDMap;
+ for (SetVector<const MDNode *>::iterator I = MD.begin(), IE = MD.end();
+ I != IE; ++I) {
+ MDNode *Dummy = MDNode::getTemporary(CalledFunc->getContext(),
+ ArrayRef<Value*>());
+ DummyNodes.push_back(Dummy);
+ MDMap[*I] = Dummy;
+ }
+
+ // Create new metadata nodes to replace the dummy nodes, replacing old
+ // metadata references with either a dummy node or an already-created new
+ // node.
+ for (SetVector<const MDNode *>::iterator I = MD.begin(), IE = MD.end();
+ I != IE; ++I) {
+ SmallVector<Value *, 4> NewOps;
+ for (unsigned i = 0, ie = (*I)->getNumOperands(); i != ie; ++i) {
+ const Value *V = (*I)->getOperand(i);
+ if (const MDNode *M = dyn_cast<MDNode>(V))
+ NewOps.push_back(MDMap[M]);
+ else
+ NewOps.push_back(const_cast<Value *>(V));
+ }
+
+ MDNode *NewM = MDNode::get(CalledFunc->getContext(), NewOps),
+ *TempM = MDMap[*I];
+
+ TempM->replaceAllUsesWith(NewM);
+ }
+
+ // Now replace the metadata in the new inlined instructions with the
+ // repacements from the map.
+ for (ValueToValueMapTy::iterator VMI = VMap.begin(), VMIE = VMap.end();
+ VMI != VMIE; ++VMI) {
+ if (!VMI->second)
+ continue;
+
+ Instruction *NI = dyn_cast<Instruction>(VMI->second);
+ if (!NI)
+ continue;
+
+ if (MDNode *M = NI->getMetadata(LLVMContext::MD_alias_scope))
+ NI->setMetadata(LLVMContext::MD_alias_scope, MDMap[M]);
+
+ if (MDNode *M = NI->getMetadata(LLVMContext::MD_noalias))
+ NI->setMetadata(LLVMContext::MD_noalias, MDMap[M]);
+ }
+
+ // Now that everything has been replaced, delete the dummy nodes.
+ for (unsigned i = 0, ie = DummyNodes.size(); i != ie; ++i)
+ MDNode::deleteTemporary(DummyNodes[i]);
+}
+
/// UpdateCallGraphAfterInlining - Once we have cloned code over from a callee
/// into the caller, update the specified callgraph to reflect the changes we
/// made. Note that it's possible that not all code was copied over, so only
// Update inlined instructions' line number information.
fixupLineNumbers(Caller, FirstNewBlock, TheCall);
+
+ // Clone existing noalias metadata if necessary.
+ CloneAliasScopeMetadata(CS, VMap);
}
// If there are any alloca instructions in the block that used to be the entry
case LLVMContext::MD_tbaa:
K->setMetadata(Kind, MDNode::getMostGenericTBAA(JMD, KMD));
break;
+ case LLVMContext::MD_alias_scope:
+ case LLVMContext::MD_noalias:
+ K->setMetadata(Kind, MDNode::intersect(JMD, KMD));
+ break;
case LLVMContext::MD_fpmath:
K->setMetadata(Kind, MDNode::getMostGenericFPMath(JMD, KMD));
break;
// non-speculated memory access when the condition was false, this would be
// caught by the runtime overlap checks).
if (Kind != LLVMContext::MD_tbaa &&
+ Kind != LLVMContext::MD_alias_scope &&
+ Kind != LLVMContext::MD_noalias &&
Kind != LLVMContext::MD_fpmath)
continue;
case LLVMContext::MD_tbaa:
MD = MDNode::getMostGenericTBAA(MD, IMD);
break;
+ case LLVMContext::MD_alias_scope:
+ case LLVMContext::MD_noalias:
+ MD = MDNode::intersect(MD, IMD);
+ break;
case LLVMContext::MD_fpmath:
MD = MDNode::getMostGenericFPMath(MD, IMD);
break;
--- /dev/null
+; RUN: opt < %s -basicaa -scoped-noalias -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"
+
+define void @foo1(float* nocapture %a, float* nocapture readonly %c) #0 {
+entry:
+; CHECK-LABEL: Function: foo1
+ %0 = load float* %c, align 4, !alias.scope !0
+ %arrayidx.i = getelementptr inbounds float* %a, i64 5
+ store float %0, float* %arrayidx.i, align 4, !noalias !0
+
+ %1 = load float* %c, align 4
+ %arrayidx = getelementptr inbounds float* %a, i64 7
+ store float %1, float* %arrayidx, align 4
+
+ %2 = load float* %c, align 4, !alias.scope !1
+ %arrayidx.i2 = getelementptr inbounds float* %a, i64 15
+ store float %2, float* %arrayidx.i2, align 4, !noalias !3
+
+ %3 = load float* %c, align 4, !alias.scope !3
+ %arrayidx.i3 = getelementptr inbounds float* %a, i64 16
+ store float %3, float* %arrayidx.i3, align 4, !noalias !0
+
+ %4 = load float* %c, align 4, !alias.scope !5
+ %arrayidx.i4 = getelementptr inbounds float* %a, i64 17
+ store float %4, float* %arrayidx.i4, align 4, !noalias !3
+ ret void
+}
+
+attributes #0 = { nounwind uwtable }
+
+; A root scope (which doubles as a list of itself):
+!0 = metadata !{metadata !0}
+
+; Two child scopes (which must be self-referential to avoid being "uniqued"):
+!1 = metadata !{metadata !2}
+!2 = metadata !{metadata !2, metadata !0}
+
+!3 = metadata !{metadata !4}
+!4 = metadata !{metadata !4, metadata !0}
+
+; A list of the two children:
+!5 = metadata !{metadata !2, metadata !4}
+
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %1, float* %arrayidx, align 4
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %3, float* %arrayidx.i3, align 4, !noalias !0
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %4, float* %arrayidx.i4, align 4, !noalias !3
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %1, float* %arrayidx, align 4
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %3, float* %arrayidx.i3, align 4, !noalias !0
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %4, float* %arrayidx.i4, align 4, !noalias !3
+; CHECK: NoAlias: %2 = load float* %c, align 4, !alias.scope !1 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %2 = load float* %c, align 4, !alias.scope !1 <-> store float %1, float* %arrayidx, align 4
+; CHECK: MayAlias: %2 = load float* %c, align 4, !alias.scope !1 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: NoAlias: %2 = load float* %c, align 4, !alias.scope !1 <-> store float %3, float* %arrayidx.i3, align 4, !noalias !0
+; CHECK: MayAlias: %2 = load float* %c, align 4, !alias.scope !1 <-> store float %4, float* %arrayidx.i4, align 4, !noalias !3
+; CHECK: NoAlias: %3 = load float* %c, align 4, !alias.scope !3 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %3 = load float* %c, align 4, !alias.scope !3 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: %3 = load float* %c, align 4, !alias.scope !3 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: NoAlias: %3 = load float* %c, align 4, !alias.scope !3 <-> store float %3, float* %arrayidx.i3, align 4, !noalias !0
+; CHECK: NoAlias: %3 = load float* %c, align 4, !alias.scope !3 <-> store float %4, float* %arrayidx.i4, align 4, !noalias !3
+; CHECK: NoAlias: %4 = load float* %c, align 4, !alias.scope !5 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %4 = load float* %c, align 4, !alias.scope !5 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: %4 = load float* %c, align 4, !alias.scope !5 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: NoAlias: %4 = load float* %c, align 4, !alias.scope !5 <-> store float %3, float* %arrayidx.i3, align 4, !noalias !0
+; CHECK: NoAlias: %4 = load float* %c, align 4, !alias.scope !5 <-> store float %4, float* %arrayidx.i4, align 4, !noalias !3
+; CHECK: NoAlias: store float %1, float* %arrayidx, align 4 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: NoAlias: store float %2, float* %arrayidx.i2, align 4, !noalias !3 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: NoAlias: store float %2, float* %arrayidx.i2, align 4, !noalias !3 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: store float %3, float* %arrayidx.i3, align 4, !noalias !0 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: NoAlias: store float %3, float* %arrayidx.i3, align 4, !noalias !0 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: store float %3, float* %arrayidx.i3, align 4, !noalias !0 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: NoAlias: store float %4, float* %arrayidx.i4, align 4, !noalias !3 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: NoAlias: store float %4, float* %arrayidx.i4, align 4, !noalias !3 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: store float %4, float* %arrayidx.i4, align 4, !noalias !3 <-> store float %2, float* %arrayidx.i2, align 4, !noalias !3
+; CHECK: NoAlias: store float %4, float* %arrayidx.i4, align 4, !noalias !3 <-> store float %3, float* %arrayidx.i3, align 4, !noalias !0
+
--- /dev/null
+; RUN: opt < %s -basicaa -scoped-noalias -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"
+
+define void @foo1(float* nocapture %a, float* nocapture readonly %c) #0 {
+entry:
+; CHECK-LABEL: Function: foo1
+ %0 = load float* %c, align 4, !alias.scope !0
+ %arrayidx.i = getelementptr inbounds float* %a, i64 5
+ store float %0, float* %arrayidx.i, align 4, !noalias !0
+ %1 = load float* %c, align 4
+ %arrayidx = getelementptr inbounds float* %a, i64 7
+ store float %1, float* %arrayidx, align 4
+ ret void
+
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %1, float* %arrayidx, align 4
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: store float %1, float* %arrayidx, align 4 <-> store float %0, float* %arrayidx.i, align 4, !noalias !0
+}
+
+attributes #0 = { nounwind uwtable }
+
+!0 = metadata !{metadata !0}
+
--- /dev/null
+; RUN: opt < %s -basicaa -scoped-noalias -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"
+
+define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+entry:
+; CHECK-LABEL: Function: foo2
+ %0 = load float* %c, align 4, !alias.scope !0
+ %arrayidx.i = getelementptr inbounds float* %a, i64 5
+ store float %0, float* %arrayidx.i, align 4, !alias.scope !2, !noalias !1
+ %arrayidx1.i = getelementptr inbounds float* %b, i64 8
+ store float %0, float* %arrayidx1.i, align 4, !alias.scope !1, !noalias !2
+ %1 = load float* %c, align 4
+ %arrayidx = getelementptr inbounds float* %a, i64 7
+ store float %1, float* %arrayidx, align 4
+ ret void
+
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %0, float* %arrayidx.i, align 4, !alias.scope !2, !noalias !1
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %0, float* %arrayidx1.i, align 4, !alias.scope !1, !noalias !2
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %1, float* %arrayidx, align 4
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %0, float* %arrayidx.i, align 4, !alias.scope !2, !noalias !1
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %0, float* %arrayidx1.i, align 4, !alias.scope !1, !noalias !2
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %1, float* %arrayidx, align 4
+; CHECK: NoAlias: store float %0, float* %arrayidx1.i, align 4, !alias.scope !1, !noalias !2 <-> store float %0, float* %arrayidx.i, align 4, !alias.scope !2, !noalias !1
+; CHECK: NoAlias: store float %1, float* %arrayidx, align 4 <-> store float %0, float* %arrayidx.i, align 4, !alias.scope !2, !noalias !1
+; CHECK: MayAlias: store float %1, float* %arrayidx, align 4 <-> store float %0, float* %arrayidx1.i, align 4, !alias.scope !1, !noalias !2
+}
+
+attributes #0 = { nounwind uwtable }
+
+!0 = metadata !{metadata !1, metadata !2}
+!1 = metadata !{metadata !1}
+!2 = metadata !{metadata !2}
+
--- /dev/null
+; RUN: opt -scoped-noalias -basicaa -gvn -S < %s | FileCheck %s
+
+define i32 @test1(i32* %p, i32* %q) {
+; CHECK-LABEL: @test1(i32* %p, i32* %q)
+; CHECK: load i32* %p
+; CHECK-NOT: noalias
+; CHECK: %c = add i32 %a, %a
+ %a = load i32* %p, !noalias !0
+ %b = load i32* %p
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+define i32 @test2(i32* %p, i32* %q) {
+; CHECK-LABEL: @test2(i32* %p, i32* %q)
+; CHECK: load i32* %p, !alias.scope !0
+; CHECK: %c = add i32 %a, %a
+ %a = load i32* %p, !alias.scope !0
+ %b = load i32* %p, !alias.scope !0
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+; FIXME: In this case we can do better than intersecting the scopes, and can
+; concatenate them instead. Both loads are in the same basic block, the first
+; makes the second safe to speculatively execute, and there are no calls that may
+; throw in between.
+define i32 @test3(i32* %p, i32* %q) {
+; CHECK-LABEL: @test3(i32* %p, i32* %q)
+; CHECK: load i32* %p, !alias.scope !1
+; CHECK: %c = add i32 %a, %a
+ %a = load i32* %p, !alias.scope !1
+ %b = load i32* %p, !alias.scope !2
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+declare i32 @foo(i32*) readonly
+
+!0 = metadata !{metadata !0}
+!1 = metadata !{metadata !1}
+!2 = metadata !{metadata !0, metadata !1}
+