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
+Each type of metadata specifies a list of scopes where each scope has an id and
+a domain. When evaluating an aliasing query, if for some some domain, the set
+of scopes with that domain in one instruction's ``alias.scope`` list is a
+subset of (or qual to) the set of scopes for that domain in another
+instruction's ``noalias`` list, then the two memory accesses are assumed not to
+alias.
+
+The metadata identifying each domain is itself a list containing one or two
+entries. The first entry is the name of the domain. 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.
+self-reference can be used to create globally unique domain names. A
+descriptive string may optionally be provided as a second list entry.
+
+The metadata identifying each scope is also itself a list containing two or
+three 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. A metadata
+reference to the scope's domain is the second entry. A descriptive string may
+optionally be provided as a third list entry.
For example,
.. code-block:: llvm
- ; A root scope (which doubles as a list of itself):
+ ; Two scope domains:
!0 = metadata !{metadata !0}
+ !1 = metadata !{metadata !1}
- ; 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
+ ; Some scopes in these domains:
+ !2 = metadata !{metadata !2, metadata !0}
+ !3 = metadata !{metadata !3, metadata !0}
+ !4 = metadata !{metadata !4, metadata !1}
- !3 = metadata !{metadata !4} ; A list containing only scope !4
- !4 = metadata !{metadata !4, metadata !0} ; Scope !4 is a descendant of scope !0
+ ; Some scope lists:
+ !5 = metadata !{metadata !4} ; A list containing only scope !4
+ !6 = metadata !{metadata !4, metadata !3, metadata !2}
+ !7 = metadata !{metadata !3}
; 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
+ %0 = load float* %c, align 4, !alias.scope !5
+ store float %0, float* %arrayidx.i, align 4, !noalias !5
+
+ ; These two instructions also don't alias (for domain !1, the set of scopes
+ ; in the !alias.scope equals that in the !noalias list):
+ %2 = load float* %c, align 4, !alias.scope !5
+ store float %2, float* %arrayidx.i2, align 4, !noalias !6
+
+ ; These two instructions don't alias (for domain !0, the set of scopes in
+ ; the !noalias list is not a superset of, or equal to, the scopes in the
+ ; !alias.scope list):
+ %2 = load float* %c, align 4, !alias.scope !6
+ store float %0, float* %arrayidx.i, align 4, !noalias !7
'``fpmath``' Metadata
^^^^^^^^^^^^^^^^^^^^^
/// \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());
+ MDNode *createAnonymousAARoot(StringRef Name = StringRef(),
+ MDNode *Extra = nullptr);
public:
/// \brief Return metadata appropriate for a TBAA root node. Each returned
return createAnonymousAARoot();
}
- /// \brief Return metadata appropriate for an alias scope root node.
+ /// \brief Return metadata appropriate for an alias scope domain node.
/// Each returned node is distinct from all other metadata and will never
/// be identified (uniqued) with anything else.
- MDNode *createAnonymousAliasScopeRoot(StringRef Name = StringRef()) {
+ MDNode *createAnonymousAliasScopeDomain(StringRef Name = StringRef()) {
return createAnonymousAARoot(Name);
}
+ /// \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 *createAnonymousAliasScope(MDNode *Domain,
+ StringRef Name = StringRef()) {
+ return createAnonymousAARoot(Name, Domain);
+ }
+
/// \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
+ /// \brief Return metadata appropriate for an alias scope domain node with
/// the given name. This may be identified (uniqued) with other roots with
/// the same name.
- MDNode *createAliasScopeRoot(StringRef Name);
+ MDNode *createAliasScopeDomain(StringRef Name);
+
+ /// \brief Return metadata appropriate for an alias scope node with
+ /// the given name. This may be identified (uniqued) with other scopes with
+ /// the same name and domain.
+ MDNode *createAliasScope(StringRef Name, MDNode *Domain);
/// \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;
// 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:
+// Alias-analysis scopes are defined by an id (which can be a string or some
+// other metadata node), a domain node, and an optional descriptive string.
+// A domain is defined by an id (which can be a string or some other metadata
+// node), and an optional descriptive string.
//
-// !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 }
+// !dom0 = metadata !{ metadata !"domain of foo()" }
+// !scope1 = metadata !{ metadata !scope1, metadata !dom0, metadata !"scope 1" }
+// !scope2 = metadata !{ metadata !scope2, metadata !dom0, metadata !"scope 2" }
//
// Loads and stores can be tagged with an alias-analysis scope, and also, with
// a noalias tag for a specific scope:
// ... = 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
+// has a set of noalias scopes in some domain that is superset of the alias
+// scopes in that domain of some 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/ADT/SmallPtrSet.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/IR/Constants.h"
/// getNode - Get the MDNode for this AliasScopeNode.
const MDNode *getNode() const { return Node; }
- /// getParent - Get this AliasScopeNode's Alias tree parent.
- AliasScopeNode getParent() const {
+ /// getDomain - Get the MDNode for this AliasScopeNode's domain.
+ const MDNode *getDomain() 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);
+ return nullptr;
+ return dyn_cast_or_null<MDNode>(Node->getOperand(1));
}
};
}
protected:
- bool mayAlias(const MDNode *A, const MDNode *B) const;
bool mayAliasInScopes(const MDNode *Scopes, const MDNode *NoAlias) const;
+ void collectMDInDomain(const MDNode *List, const MDNode *Domain,
+ SmallPtrSetImpl<const MDNode *> &Nodes) const;
private:
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
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;
+void
+ScopedNoAliasAA::collectMDInDomain(const MDNode *List, const MDNode *Domain,
+ SmallPtrSetImpl<const MDNode *> &Nodes) const {
+ for (unsigned i = 0, ie = List->getNumOperands(); i != ie; ++i)
+ if (const MDNode *MD = dyn_cast<MDNode>(List->getOperand(i)))
+ if (AliasScopeNode(MD).getDomain() == Domain)
+ Nodes.insert(MD);
}
bool
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;
+ // Collect the set of scope domains relevant to the noalias scopes.
+ SmallPtrSet<const MDNode *, 16> Domains;
+ for (unsigned i = 0, ie = NoAlias->getNumOperands(); i != ie; ++i)
+ if (const MDNode *NAMD = dyn_cast<MDNode>(NoAlias->getOperand(i)))
+ if (const MDNode *Domain = AliasScopeNode(NAMD).getDomain())
+ Domains.insert(Domain);
+
+ // We alias unless, for some domain, the set of noalias scopes in that domain
+ // is a superset of the set of alias scopes in that domain.
+ for (const MDNode *Domain : Domains) {
+ SmallPtrSet<const MDNode *, 16> NANodes, ScopeNodes;
+ collectMDInDomain(NoAlias, Domain, NANodes);
+ collectMDInDomain(Scopes, Domain, ScopeNodes);
+ if (!ScopeNodes.size())
+ continue;
+
+ // To not alias, all of the nodes in ScopeNodes must be in NANodes.
+ bool FoundAll = true;
+ for (const MDNode *SMD : ScopeNodes)
+ if (!NANodes.count(SMD)) {
+ FoundAll = false;
+ break;
+ }
+
+ if (FoundAll)
+ return false;
+ }
- return true;
+ return true;
}
AliasAnalysis::AliasResult
return MDNode::get(Context, Range);
}
-MDNode *MDBuilder::createAnonymousAARoot(StringRef Name) {
+MDNode *MDBuilder::createAnonymousAARoot(StringRef Name, MDNode *Extra) {
// To ensure uniqueness the root node is self-referential.
MDNode *Dummy = MDNode::getTemporary(Context, ArrayRef<Value*>());
- SmallVector<Value *, 2> Args(1, Dummy);
+ SmallVector<Value *, 3> Args(1, Dummy);
+ if (Extra)
+ Args.push_back(Extra);
if (!Name.empty())
Args.push_back(createString(Name));
MDNode *Root = MDNode::get(Context, Args);
}
}
-MDNode *MDBuilder::createAliasScopeRoot(StringRef Name) {
+MDNode *MDBuilder::createAliasScopeDomain(StringRef Name) {
return MDNode::get(Context, createString(Name));
}
-MDNode *MDBuilder::createAliasScopeNode(StringRef Name, MDNode *Parent) {
- Value *Ops[2] = { createString(Name), Parent };
+MDNode *MDBuilder::createAliasScope(StringRef Name, MDNode *Domain) {
+ Value *Ops[2] = { createString(Name), Domain };
return MDNode::get(Context, Ops);
}
--- /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 !9
+ %arrayidx.i = getelementptr inbounds float* %a, i64 5
+ store float %0, float* %arrayidx.i, align 4, !noalias !6
+
+ %1 = load float* %c, align 4, !alias.scope !5
+ %arrayidx.i2 = getelementptr inbounds float* %a, i64 15
+ store float %1, float* %arrayidx.i2, align 4, !noalias !6
+
+ %2 = load float* %c, align 4, !alias.scope !6
+ %arrayidx.i3 = getelementptr inbounds float* %a, i64 16
+ store float %2, float* %arrayidx.i3, align 4, !noalias !5
+
+ ret void
+}
+
+attributes #0 = { nounwind uwtable }
+
+!0 = metadata !{metadata !0, metadata !"some domain"}
+!1 = metadata !{metadata !1, metadata !"some other domain"}
+
+; Two scopes (which must be self-referential to avoid being "uniqued"):
+!2 = metadata !{metadata !2, metadata !0, metadata !"a scope in dom0"}
+!3 = metadata !{metadata !2}
+
+!4 = metadata !{metadata !4, metadata !0, metadata !"another scope in dom0"}
+!5 = metadata !{metadata !4}
+
+; A list of the two scopes.
+!6 = metadata !{metadata !2, metadata !4}
+
+; Another scope in the second domain
+!7 = metadata !{metadata !7, metadata !1, metadata !"another scope in dom1"}
+!8 = metadata !{metadata !7}
+
+; A list of scopes from both domains.
+!9 = metadata !{metadata !2, metadata !4, metadata !7}
+
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %0, float* %arrayidx.i, align 4, !noalias !6
+; CHECK: NoAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %1, float* %arrayidx.i2, align 4, !noalias !6
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %2, float* %arrayidx.i3, align 4, !noalias !7
+; CHECK: NoAlias: %1 = load float* %c, align 4, !alias.scope !7 <-> store float %0, float* %arrayidx.i, align 4, !noalias !6
+; CHECK: NoAlias: %1 = load float* %c, align 4, !alias.scope !7 <-> store float %1, float* %arrayidx.i2, align 4, !noalias !6
+; CHECK: NoAlias: %1 = load float* %c, align 4, !alias.scope !7 <-> store float %2, float* %arrayidx.i3, align 4, !noalias !7
+; CHECK: NoAlias: %2 = load float* %c, align 4, !alias.scope !6 <-> store float %0, float* %arrayidx.i, align 4, !noalias !6
+; CHECK: NoAlias: %2 = load float* %c, align 4, !alias.scope !6 <-> store float %1, float* %arrayidx.i2, align 4, !noalias !6
+; CHECK: MayAlias: %2 = load float* %c, align 4, !alias.scope !6 <-> store float %2, float* %arrayidx.i3, align 4, !noalias !7
+; 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
+
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
+ %0 = load float* %c, align 4, !alias.scope !1
%arrayidx.i = getelementptr inbounds float* %a, i64 5
- store float %0, float* %arrayidx.i, align 4, !noalias !0
+ store float %0, float* %arrayidx.i, align 4, !noalias !1
%1 = load float* %c, align 4
%arrayidx = getelementptr inbounds float* %a, i64 7
store float %1, float* %arrayidx, align 4
attributes #0 = { nounwind uwtable }
-!0 = metadata !{metadata !0}
+!0 = metadata !{metadata !0, metadata !"some domain"}
+!1 = metadata !{metadata !1, metadata !0, metadata !"some scope"}
; 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
+ store float %0, float* %arrayidx.i, align 4, !alias.scope !5, !noalias !4
%arrayidx1.i = getelementptr inbounds float* %b, i64 8
- store float %0, float* %arrayidx1.i, align 4, !alias.scope !1, !noalias !2
+ store float %0, float* %arrayidx1.i, align 4, !alias.scope !0, !noalias !5
%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 %0, float* %arrayidx.i, align 4, !alias.scope !4, !noalia
+; CHECK: s !5
+; CHECK: MayAlias: %0 = load float* %c, align 4, !alias.scope !0 <-> store float %0, float* %arrayidx1.i, align 4, !alias.scope !0, !noali
+; CHECK: as !4
; 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 %0, float* %arrayidx.i, align 4, !alias.scope !4, !noalias !5
+; CHECK: MayAlias: %1 = load float* %c, align 4 <-> store float %0, float* %arrayidx1.i, align 4, !alias.scope !0, !noalias !4
; 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
+; CHECK: NoAlias: store float %0, float* %arrayidx1.i, align 4, !alias.scope !0, !noalias !4 <-> store float %0, float* %arrayidx.i, align
+; CHECK: 4, !alias.scope !4, !noalias !5
+; CHECK: NoAlias: store float %1, float* %arrayidx, align 4 <-> store float %0, float* %arrayidx.i, align 4, !alias.scope !4, !noalias !5
+; CHECK: MayAlias: store float %1, float* %arrayidx, align 4 <-> store float %0, float* %arrayidx1.i, align 4, !alias.scope !0, !noalias !
+; CHECK: 4
}
attributes #0 = { nounwind uwtable }
-!0 = metadata !{metadata !1, metadata !2}
-!1 = metadata !{metadata !1}
-!2 = metadata !{metadata !2}
+!0 = metadata !{metadata !1, metadata !3}
+!1 = metadata !{metadata !1, metadata !2, metadata !"some scope"}
+!2 = metadata !{metadata !2, metadata !"some domain"}
+!3 = metadata !{metadata !3, metadata !2, metadata !"some other scope"}
+!4 = metadata !{metadata !1}
+!5 = metadata !{metadata !3}