From 029cde639c9b773791ea8d10a4490aed9852f6a6 Mon Sep 17 00:00:00 2001 From: Hal Finkel Date: Fri, 25 Jul 2014 15:50:02 +0000 Subject: [PATCH] Simplify and improve scoped-noalias metadata semantics In the process of fixing the noalias parameter -> metadata conversion process that will take place during inlining (which will be committed soon, but not turned on by default), I have come to realize that the semantics provided by yesterday's commit are not really what we want. Here's why: void foo(noalias a, noalias b, noalias c, bool x) { *q = x ? a : b; *c = *q; } Generically, we know that *c does not alias with *a and with *b (so there is an 'and' in what we know we're not), and we know that *q might be derived from *a or from *b (so there is an 'or' in what we know that we are). So we do not want the semantics currently, where any noalias scope matching any alias.scope causes a NoAlias return. What we want to know is that the noalias scopes form a superset of the alias.scope list (meaning that all the things we know we're not is a superset of all of things the other instruction might be). Making that change, however, introduces a composibility problem. If we inline once, adding the noalias metadata, and then inline again adding more, and we append new scopes onto the noalias and alias.scope lists each time. But, this means that we could change what was a NoAlias result previously into a MayAlias result because we appended an additional scope onto one of the alias.scope lists. So, instead of giving scopes the ability to have parents (which I had borrowed from the TBAA implementation, but seems increasingly unlikely to be useful in practice), I've given them domains. The subset/superset condition now applies within each domain independently, and we only need it to hold in one domain. Each time we inline, we add the new scopes in a new scope domain, and everything now composes nicely. In addition, this simplifies the implementation. llvm-svn: 213948 --- llvm/docs/LangRef.rst | 74 ++++++++-------- llvm/include/llvm/IR/MDBuilder.h | 28 +++++-- llvm/lib/Analysis/ScopedNoAliasAA.cpp | 98 +++++++++++----------- llvm/lib/IR/MDBuilder.cpp | 12 +-- .../test/Analysis/ScopedNoAliasAA/basic-domains.ll | 57 +++++++++++++ llvm/test/Analysis/ScopedNoAliasAA/basic.ll | 7 +- llvm/test/Analysis/ScopedNoAliasAA/basic2.ll | 31 ++++--- 7 files changed, 198 insertions(+), 109 deletions(-) create mode 100644 llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index ddbf400..891b9c0 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2837,50 +2837,58 @@ 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 +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 ^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/IR/MDBuilder.h b/llvm/include/llvm/IR/MDBuilder.h index 6672b14..d29512c 100644 --- a/llvm/include/llvm/IR/MDBuilder.h +++ b/llvm/include/llvm/IR/MDBuilder.h @@ -70,7 +70,8 @@ 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()); + MDNode *createAnonymousAARoot(StringRef Name = StringRef(), + MDNode *Extra = nullptr); public: /// \brief Return metadata appropriate for a TBAA root node. Each returned @@ -80,32 +81,41 @@ public: 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; diff --git a/llvm/lib/Analysis/ScopedNoAliasAA.cpp b/llvm/lib/Analysis/ScopedNoAliasAA.cpp index f197f1c..d090227 100644 --- a/llvm/lib/Analysis/ScopedNoAliasAA.cpp +++ b/llvm/lib/Analysis/ScopedNoAliasAA.cpp @@ -10,13 +10,14 @@ // 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: @@ -25,17 +26,13 @@ // ... = 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" @@ -66,15 +63,11 @@ public: /// 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(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(Node->getOperand(1)); } }; @@ -102,8 +95,9 @@ public: } 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 &Nodes) const; private: virtual void getAnalysisUsage(AnalysisUsage &AU) const; @@ -133,24 +127,13 @@ ScopedNoAliasAA::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 &Nodes) const { + for (unsigned i = 0, ie = List->getNumOperands(); i != ie; ++i) + if (const MDNode *MD = dyn_cast(List->getOperand(i))) + if (AliasScopeNode(MD).getDomain() == Domain) + Nodes.insert(MD); } bool @@ -159,14 +142,35 @@ ScopedNoAliasAA::mayAliasInScopes(const MDNode *Scopes, if (!Scopes || !NoAlias) return true; - for (unsigned i = 0, ie = Scopes->getNumOperands(); i != ie; ++i) - if (const MDNode *SMD = dyn_cast(Scopes->getOperand(i))) - for (unsigned j = 0, je = NoAlias->getNumOperands(); j != je; ++j) - if (const MDNode *NAMD = dyn_cast(NoAlias->getOperand(j))) - if (!mayAlias(SMD, NAMD)) - return false; + // Collect the set of scope domains relevant to the noalias scopes. + SmallPtrSet Domains; + for (unsigned i = 0, ie = NoAlias->getNumOperands(); i != ie; ++i) + if (const MDNode *NAMD = dyn_cast(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 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 diff --git a/llvm/lib/IR/MDBuilder.cpp b/llvm/lib/IR/MDBuilder.cpp index 103915f..39307a2 100644 --- a/llvm/lib/IR/MDBuilder.cpp +++ b/llvm/lib/IR/MDBuilder.cpp @@ -60,11 +60,13 @@ MDNode *MDBuilder::createRange(const APInt &Lo, const APInt &Hi) { 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()); - SmallVector Args(1, Dummy); + SmallVector Args(1, Dummy); + if (Extra) + Args.push_back(Extra); if (!Name.empty()) Args.push_back(createString(Name)); MDNode *Root = MDNode::get(Context, Args); @@ -98,12 +100,12 @@ MDNode *MDBuilder::createTBAANode(StringRef Name, MDNode *Parent, } } -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); } diff --git a/llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll b/llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll new file mode 100644 index 0000000..d88a496 --- /dev/null +++ b/llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll @@ -0,0 +1,57 @@ +; 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 + diff --git a/llvm/test/Analysis/ScopedNoAliasAA/basic.ll b/llvm/test/Analysis/ScopedNoAliasAA/basic.ll index bae977f..73fe333 100644 --- a/llvm/test/Analysis/ScopedNoAliasAA/basic.ll +++ b/llvm/test/Analysis/ScopedNoAliasAA/basic.ll @@ -5,9 +5,9 @@ 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 + %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 @@ -22,5 +22,6 @@ entry: attributes #0 = { nounwind uwtable } -!0 = metadata !{metadata !0} +!0 = metadata !{metadata !0, metadata !"some domain"} +!1 = metadata !{metadata !1, metadata !0, metadata !"some scope"} diff --git a/llvm/test/Analysis/ScopedNoAliasAA/basic2.ll b/llvm/test/Analysis/ScopedNoAliasAA/basic2.ll index 44393bb..37b0add 100644 --- a/llvm/test/Analysis/ScopedNoAliasAA/basic2.ll +++ b/llvm/test/Analysis/ScopedNoAliasAA/basic2.ll @@ -7,28 +7,35 @@ 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 + 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} -- 2.7.4