ScopedNoAliasAA.cpp [plain text]
#include "llvm/ADT/SmallPtrSet.h"
#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;
static cl::opt<bool>
EnableScopedNoAlias("enable-scoped-noalias", cl::init(true));
namespace {
class AliasScopeNode {
const MDNode *Node;
public:
AliasScopeNode() : Node(0) {}
explicit AliasScopeNode(const MDNode *N) : Node(N) {}
const MDNode *getNode() const { return Node; }
const MDNode *getDomain() const {
if (Node->getNumOperands() < 2)
return nullptr;
return dyn_cast_or_null<MDNode>(Node->getOperand(1));
}
};
class ScopedNoAliasAA : public ImmutablePass, public AliasAnalysis {
public:
static char ID; ScopedNoAliasAA() : ImmutablePass(ID) {
initializeScopedNoAliasAAPass(*PassRegistry::getPassRegistry());
}
void initializePass() override { InitializeAliasAnalysis(this); }
void *getAdjustedAnalysisPointer(const void *PI) override {
if (PI == &AliasAnalysis::ID)
return (AliasAnalysis*)this;
return this;
}
protected:
bool mayAliasInScopes(const MDNode *Scopes, const MDNode *NoAlias) const;
void collectMDInDomain(const MDNode *List, const MDNode *Domain,
SmallPtrSetImpl<const MDNode *> &Nodes) const;
private:
void getAnalysisUsage(AnalysisUsage &AU) const override;
AliasResult alias(const Location &LocA, const Location &LocB) override;
bool pointsToConstantMemory(const Location &Loc, bool OrLocal) override;
ModRefBehavior getModRefBehavior(ImmutableCallSite CS) override;
ModRefBehavior getModRefBehavior(const Function *F) override;
ModRefResult getModRefInfo(ImmutableCallSite CS,
const Location &Loc) override;
ModRefResult getModRefInfo(ImmutableCallSite CS1,
ImmutableCallSite CS2) override;
};
}
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);
}
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
ScopedNoAliasAA::mayAliasInScopes(const MDNode *Scopes,
const MDNode *NoAlias) const {
if (!Scopes || !NoAlias)
return true;
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);
for (const MDNode *Domain : Domains) {
SmallPtrSet<const MDNode *, 16> NANodes, ScopeNodes;
collectMDInDomain(NoAlias, Domain, NANodes);
collectMDInDomain(Scopes, Domain, ScopeNodes);
if (!ScopeNodes.size())
continue;
bool FoundAll = true;
for (const MDNode *SMD : ScopeNodes)
if (!NANodes.count(SMD)) {
FoundAll = false;
break;
}
if (FoundAll)
return false;
}
return true;
}
AliasAnalysis::AliasResult
ScopedNoAliasAA::alias(const Location &LocA, const Location &LocB) {
if (!EnableScopedNoAlias)
return AliasAnalysis::alias(LocA, LocB);
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;
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);
}