243 changes: 243 additions & 0 deletions llvm/lib/Analysis/ScopedNoAliasAA.cpp
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);
}

12 changes: 12 additions & 0 deletions llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,5 +618,17 @@ void Instruction::getAAMetadata(AAMDNodes &N, bool Merge) const {
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);
}

28 changes: 28 additions & 0 deletions llvm/lib/CodeGen/MachineInstr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,34 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const MachineMemOperand &MMO) {
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)";
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/Passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ void TargetPassConfig::addIRPasses() {
// 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
Expand Down
33 changes: 27 additions & 6 deletions llvm/lib/IR/IRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ static CallInst *createCallHelper(Value *Callee, ArrayRef<Value *> Ops,

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() };
Expand All @@ -74,13 +75,20 @@ CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align,
// 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);

Expand All @@ -98,13 +106,20 @@ CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align,
// 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);

Expand All @@ -118,7 +133,13 @@ CreateMemMove(Value *Dst, Value *Src, Value *Size, unsigned Align,
// 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;
}

Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/IR/LLVMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
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; }

Expand Down
20 changes: 17 additions & 3 deletions llvm/lib/IR/MDBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,15 @@ MDNode *MDBuilder::createRange(const APInt &Lo, const APInt &Hi) {
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
Expand Down Expand Up @@ -93,6 +98,15 @@ MDNode *MDBuilder::createTBAANode(StringRef Name, MDNode *Parent,
}
}

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) {
Expand Down
37 changes: 37 additions & 0 deletions llvm/lib/IR/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,41 @@ void MDNode::replaceOperand(MDNodeOperand *Op, Value *To) {
}
}

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;
Expand Down Expand Up @@ -689,6 +724,8 @@ void Instruction::setMetadata(unsigned KindID, MDNode *Node) {

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 {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ PassManagerBuilder::addInitialAliasAnalysisPasses(PassManagerBase &PM) 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());
}

Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Transforms/Scalar/GVN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,19 @@ static void patchReplacementInstruction(Instruction *I, Value *Repl) {
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;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Scalar/Scalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM) {
unwrap(PM)->add(createTypeBasedAliasAnalysisPass());
}

void LLVMAddScopedNoAliasAAPass(LLVMPassManagerRef PM) {
unwrap(PM)->add(createScopedNoAliasAAPass());
}

void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM) {
unwrap(PM)->add(createBasicAliasAnalysisPass());
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/Scalar/Scalarizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ bool Scalarizer::canTransferMetadata(unsigned Tag) {
|| 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);
}

Expand Down
101 changes: 101 additions & 0 deletions llvm/lib/Transforms/Utils/InlineFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
//===----------------------------------------------------------------------===//

#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"
Expand All @@ -28,6 +31,7 @@
#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;
Expand Down Expand Up @@ -260,6 +264,100 @@ static void HandleInlinedInvoke(InvokeInst *II, BasicBlock *FirstNewBlock,
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
Expand Down Expand Up @@ -648,6 +746,9 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,

// 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
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Vectorize/BBVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2982,6 +2982,10 @@ namespace {
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;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ static void propagateMetadata(Instruction *To, const Instruction *From) {
// 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;

Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ static Instruction *propagateMetadata(Instruction *I, ArrayRef<Value *> VL) {
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;
Expand Down
80 changes: 80 additions & 0 deletions llvm/test/Analysis/ScopedNoAliasAA/basic-hierarchy.ll
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

26 changes: 26 additions & 0 deletions llvm/test/Analysis/ScopedNoAliasAA/basic.ll
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}

34 changes: 34 additions & 0 deletions llvm/test/Analysis/ScopedNoAliasAA/basic2.ll
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}

43 changes: 43 additions & 0 deletions llvm/test/Transforms/GVN/noalias.ll
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}