| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,243 @@ | ||
| //===- 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); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| ; 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 | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| ; 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} | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| ; 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} | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| ; 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} | ||
|
|