BasicAliasAnalysis.cpp [plain text]
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Operator.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
using namespace llvm;
static bool isKnownNonNull(const Value *V) {
if (isa<AllocaInst>(V)) return true;
if (const Argument *A = dyn_cast<Argument>(V))
return A->hasByValAttr();
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
return !GV->hasExternalWeakLinkage();
return false;
}
static bool isNonEscapingLocalObject(const Value *V) {
if (isa<AllocaInst>(V) || isNoAliasCall(V))
return !PointerMayBeCaptured(V, false, true);
if (const Argument *A = dyn_cast<Argument>(V))
if (A->hasByValAttr() || A->hasNoAliasAttr()) {
if (A->hasNoCaptureAttr())
return true;
return !PointerMayBeCaptured(V, false, true);
}
return false;
}
static bool isObjectSmallerThan(const Value *V, unsigned Size,
const TargetData &TD) {
const Type *AccessTy;
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
AccessTy = GV->getType()->getElementType();
} else if (const AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
if (!AI->isArrayAllocation())
AccessTy = AI->getType()->getElementType();
else
return false;
} else if (const CallInst* CI = extractMallocCall(V)) {
if (!isArrayMalloc(V, &TD))
if (const ConstantInt* C = dyn_cast<ConstantInt>(CI->getOperand(1)))
return (C->getZExtValue() < Size);
return false;
} else if (const Argument *A = dyn_cast<Argument>(V)) {
if (A->hasByValAttr())
AccessTy = cast<PointerType>(A->getType())->getElementType();
else
return false;
} else {
return false;
}
if (AccessTy->isSized())
return TD.getTypeAllocSize(AccessTy) < Size;
return false;
}
namespace {
struct NoAA : public ImmutablePass, public AliasAnalysis {
static char ID; NoAA() : ImmutablePass(&ID) {}
explicit NoAA(void *PID) : ImmutablePass(PID) { }
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
}
virtual void initializePass() {
TD = getAnalysisIfAvailable<TargetData>();
}
virtual AliasResult alias(const Value *V1, unsigned V1Size,
const Value *V2, unsigned V2Size) {
return MayAlias;
}
virtual void getArgumentAccesses(Function *F, CallSite CS,
std::vector<PointerAccessInfo> &Info) {
llvm_unreachable("This method may not be called on this function!");
}
virtual bool pointsToConstantMemory(const Value *P) { return false; }
virtual ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size) {
return ModRef;
}
virtual ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) {
return ModRef;
}
virtual void deleteValue(Value *V) {}
virtual void copyValue(Value *From, Value *To) {}
virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) {
if (PI->isPassID(&AliasAnalysis::ID))
return (AliasAnalysis*)this;
return this;
}
};
}
char NoAA::ID = 0;
static RegisterPass<NoAA>
U("no-aa", "No Alias Analysis (always returns 'may' alias)", true, true);
static RegisterAnalysisGroup<AliasAnalysis> V(U);
ImmutablePass *llvm::createNoAAPass() { return new NoAA(); }
namespace {
struct BasicAliasAnalysis : public NoAA {
static char ID; BasicAliasAnalysis() : NoAA(&ID) {}
AliasResult alias(const Value *V1, unsigned V1Size,
const Value *V2, unsigned V2Size) {
assert(VisitedPHIs.empty() && "VisitedPHIs must be cleared after use!");
AliasResult Alias = aliasCheck(V1, V1Size, V2, V2Size);
VisitedPHIs.clear();
return Alias;
}
ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
ModRefResult getModRefInfo(CallSite CS1, CallSite CS2);
bool pointsToConstantMemory(const Value *P);
virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) {
if (PI->isPassID(&AliasAnalysis::ID))
return (AliasAnalysis*)this;
return this;
}
private:
SmallPtrSet<const Value*, 16> VisitedPHIs;
AliasResult aliasGEP(const GEPOperator *V1, unsigned V1Size,
const Value *V2, unsigned V2Size,
const Value *UnderlyingV1, const Value *UnderlyingV2);
AliasResult aliasPHI(const PHINode *PN, unsigned PNSize,
const Value *V2, unsigned V2Size);
AliasResult aliasSelect(const SelectInst *SI, unsigned SISize,
const Value *V2, unsigned V2Size);
AliasResult aliasCheck(const Value *V1, unsigned V1Size,
const Value *V2, unsigned V2Size);
};
}
char BasicAliasAnalysis::ID = 0;
static RegisterPass<BasicAliasAnalysis>
X("basicaa", "Basic Alias Analysis (default AA impl)", false, true);
static RegisterAnalysisGroup<AliasAnalysis, true> Y(X);
ImmutablePass *llvm::createBasicAliasAnalysisPass() {
return new BasicAliasAnalysis();
}
bool BasicAliasAnalysis::pointsToConstantMemory(const Value *P) {
if (const GlobalVariable *GV =
dyn_cast<GlobalVariable>(P->getUnderlyingObject()))
return GV->isConstant();
return false;
}
AliasAnalysis::ModRefResult
BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
const Value *Object = P->getUnderlyingObject();
if (isa<AllocaInst>(Object))
if (CallInst *CI = dyn_cast<CallInst>(CS.getInstruction()))
if (CI->isTailCall())
return NoModRef;
if (!isa<Constant>(Object) && CS.getInstruction() != Object &&
isNonEscapingLocalObject(Object)) {
bool PassedAsArg = false;
unsigned ArgNo = 0;
for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
CI != CE; ++CI, ++ArgNo) {
if (!(*CI)->getType()->isPointerTy() ||
!CS.paramHasAttr(ArgNo+1, Attribute::NoCapture))
continue;
if (!isNoAlias(cast<Value>(CI), ~0U, P, ~0U)) {
PassedAsArg = true;
break;
}
}
if (!PassedAsArg)
return NoModRef;
}
IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction());
if (II == 0)
return AliasAnalysis::getModRefInfo(CS, P, Size);
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::memcpy:
case Intrinsic::memmove: {
unsigned Len = ~0U;
if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getOperand(3)))
Len = LenCI->getZExtValue();
Value *Dest = II->getOperand(1);
Value *Src = II->getOperand(2);
if (isNoAlias(Dest, Len, P, Size)) {
if (isNoAlias(Src, Len, P, Size))
return NoModRef;
return Ref;
}
break;
}
case Intrinsic::memset:
if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getOperand(3))) {
unsigned Len = LenCI->getZExtValue();
Value *Dest = II->getOperand(1);
if (isNoAlias(Dest, Len, P, Size))
return NoModRef;
}
break;
case Intrinsic::atomic_cmp_swap:
case Intrinsic::atomic_swap:
case Intrinsic::atomic_load_add:
case Intrinsic::atomic_load_sub:
case Intrinsic::atomic_load_and:
case Intrinsic::atomic_load_nand:
case Intrinsic::atomic_load_or:
case Intrinsic::atomic_load_xor:
case Intrinsic::atomic_load_max:
case Intrinsic::atomic_load_min:
case Intrinsic::atomic_load_umax:
case Intrinsic::atomic_load_umin:
if (TD) {
Value *Op1 = II->getOperand(1);
unsigned Op1Size = TD->getTypeStoreSize(Op1->getType());
if (isNoAlias(Op1, Op1Size, P, Size))
return NoModRef;
}
break;
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::invariant_start: {
unsigned PtrSize = cast<ConstantInt>(II->getOperand(1))->getZExtValue();
if (isNoAlias(II->getOperand(2), PtrSize, P, Size))
return NoModRef;
break;
}
case Intrinsic::invariant_end: {
unsigned PtrSize = cast<ConstantInt>(II->getOperand(2))->getZExtValue();
if (isNoAlias(II->getOperand(3), PtrSize, P, Size))
return NoModRef;
break;
}
}
return AliasAnalysis::getModRefInfo(CS, P, Size);
}
AliasAnalysis::ModRefResult
BasicAliasAnalysis::getModRefInfo(CallSite CS1, CallSite CS2) {
ModRefBehavior CS1B = AliasAnalysis::getModRefBehavior(CS1);
if (CS1B == DoesNotAccessMemory) return NoModRef;
ModRefBehavior CS2B = AliasAnalysis::getModRefBehavior(CS2);
if (CS2B == DoesNotAccessMemory) return NoModRef;
if (CS1B == OnlyReadsMemory && CS2B == OnlyReadsMemory)
return Ref;
return NoAA::getModRefInfo(CS1, CS2);
}
static void GetIndiceDifference(
SmallVectorImpl<std::pair<const Value*, int64_t> > &Dest,
const SmallVectorImpl<std::pair<const Value*, int64_t> > &Src) {
if (Src.empty()) return;
for (unsigned i = 0, e = Src.size(); i != e; ++i) {
const Value *V = Src[i].first;
int64_t Scale = Src[i].second;
for (unsigned j = 0, e = Dest.size(); j != e; ++j) {
if (Dest[j].first != V) continue;
if (Dest[j].second != Scale)
Dest[j].second -= Scale;
else
Dest.erase(Dest.begin()+j);
Scale = 0;
break;
}
if (Scale)
Dest.push_back(std::make_pair(V, -Scale));
}
}
AliasAnalysis::AliasResult
BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size,
const Value *V2, unsigned V2Size,
const Value *UnderlyingV1,
const Value *UnderlyingV2) {
int64_t GEP1BaseOffset;
SmallVector<std::pair<const Value*, int64_t>, 4> GEP1VariableIndices;
if (const GEPOperator *GEP2 = dyn_cast<GEPOperator>(V2)) {
AliasResult BaseAlias = aliasCheck(UnderlyingV1, ~0U, UnderlyingV2, ~0U);
if (BaseAlias != MustAlias) return BaseAlias;
const Value *GEP1BasePtr =
DecomposeGEPExpression(GEP1, GEP1BaseOffset, GEP1VariableIndices, TD);
int64_t GEP2BaseOffset;
SmallVector<std::pair<const Value*, int64_t>, 4> GEP2VariableIndices;
const Value *GEP2BasePtr =
DecomposeGEPExpression(GEP2, GEP2BaseOffset, GEP2VariableIndices, TD);
if (GEP1BasePtr != UnderlyingV1 || GEP2BasePtr != UnderlyingV2) {
assert(TD == 0 &&
"DecomposeGEPExpression and getUnderlyingObject disagree!");
return MayAlias;
}
GEP1BaseOffset -= GEP2BaseOffset;
GetIndiceDifference(GEP1VariableIndices, GEP2VariableIndices);
} else {
if (V1Size == ~0U && V2Size == ~0U)
return MayAlias;
AliasResult R = aliasCheck(UnderlyingV1, ~0U, V2, V2Size);
if (R != MustAlias)
return R;
const Value *GEP1BasePtr =
DecomposeGEPExpression(GEP1, GEP1BaseOffset, GEP1VariableIndices, TD);
if (GEP1BasePtr != UnderlyingV1) {
assert(TD == 0 &&
"DecomposeGEPExpression and getUnderlyingObject disagree!");
return MayAlias;
}
}
if (GEP1BaseOffset == 0 && GEP1VariableIndices.empty())
return MustAlias;
for (unsigned i = 0, e = GEP1VariableIndices.size();
i != e && GEP1BaseOffset;++i)
if (int64_t RemovedOffset = GEP1BaseOffset/GEP1VariableIndices[i].second)
GEP1BaseOffset -= RemovedOffset*GEP1VariableIndices[i].second;
if (GEP1BaseOffset) {
if (GEP1BaseOffset >= (int64_t)V2Size ||
GEP1BaseOffset <= -(int64_t)V1Size)
return NoAlias;
}
return MayAlias;
}
AliasAnalysis::AliasResult
BasicAliasAnalysis::aliasSelect(const SelectInst *SI, unsigned SISize,
const Value *V2, unsigned V2Size) {
if (const SelectInst *SI2 = dyn_cast<SelectInst>(V2))
if (SI->getCondition() == SI2->getCondition()) {
AliasResult Alias =
aliasCheck(SI->getTrueValue(), SISize,
SI2->getTrueValue(), V2Size);
if (Alias == MayAlias)
return MayAlias;
AliasResult ThisAlias =
aliasCheck(SI->getFalseValue(), SISize,
SI2->getFalseValue(), V2Size);
if (ThisAlias != Alias)
return MayAlias;
return Alias;
}
AliasResult Alias =
aliasCheck(SI->getTrueValue(), SISize, V2, V2Size);
if (Alias == MayAlias)
return MayAlias;
AliasResult ThisAlias =
aliasCheck(SI->getFalseValue(), SISize, V2, V2Size);
if (ThisAlias != Alias)
return MayAlias;
return Alias;
}
AliasAnalysis::AliasResult
BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize,
const Value *V2, unsigned V2Size) {
if (!VisitedPHIs.insert(PN))
return MayAlias;
if (const PHINode *PN2 = dyn_cast<PHINode>(V2))
if (PN2->getParent() == PN->getParent()) {
AliasResult Alias =
aliasCheck(PN->getIncomingValue(0), PNSize,
PN2->getIncomingValueForBlock(PN->getIncomingBlock(0)),
V2Size);
if (Alias == MayAlias)
return MayAlias;
for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) {
AliasResult ThisAlias =
aliasCheck(PN->getIncomingValue(i), PNSize,
PN2->getIncomingValueForBlock(PN->getIncomingBlock(i)),
V2Size);
if (ThisAlias != Alias)
return MayAlias;
}
return Alias;
}
SmallPtrSet<Value*, 4> UniqueSrc;
SmallVector<Value*, 4> V1Srcs;
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
Value *PV1 = PN->getIncomingValue(i);
if (isa<PHINode>(PV1))
return MayAlias;
if (UniqueSrc.insert(PV1))
V1Srcs.push_back(PV1);
}
AliasResult Alias = aliasCheck(V2, V2Size, V1Srcs[0], PNSize);
if (Alias == MayAlias)
return MayAlias;
for (unsigned i = 1, e = V1Srcs.size(); i != e; ++i) {
Value *V = V1Srcs[i];
VisitedPHIs.erase(V2);
AliasResult ThisAlias = aliasCheck(V2, V2Size, V, PNSize);
if (ThisAlias != Alias || ThisAlias == MayAlias)
return MayAlias;
}
return Alias;
}
AliasAnalysis::AliasResult
BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size,
const Value *V2, unsigned V2Size) {
V1 = V1->stripPointerCasts();
V2 = V2->stripPointerCasts();
if (V1 == V2) return MustAlias;
if (!V1->getType()->isPointerTy() || !V2->getType()->isPointerTy())
return NoAlias;
const Value *O1 = V1->getUnderlyingObject();
const Value *O2 = V2->getUnderlyingObject();
if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O1))
if (CPN->getType()->getAddressSpace() == 0)
return NoAlias;
if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O2))
if (CPN->getType()->getAddressSpace() == 0)
return NoAlias;
if (O1 != O2) {
if (isIdentifiedObject(O1) && isIdentifiedObject(O2))
return NoAlias;
if ((isa<Constant>(O1) && isIdentifiedObject(O2) && !isa<Constant>(O2)) ||
(isa<Constant>(O2) && isIdentifiedObject(O1) && !isa<Constant>(O1)))
return NoAlias;
if ((isa<Argument>(O1) && (isa<AllocaInst>(O2) || isNoAliasCall(O2))) ||
(isa<Argument>(O2) && (isa<AllocaInst>(O1) || isNoAliasCall(O1))))
return NoAlias;
if ((isa<ConstantPointerNull>(V2) && isKnownNonNull(O1)) ||
(isa<ConstantPointerNull>(V1) && isKnownNonNull(O2)))
return NoAlias;
}
if (TD)
if ((V1Size != ~0U && isObjectSmallerThan(O2, V1Size, *TD)) ||
(V2Size != ~0U && isObjectSmallerThan(O1, V2Size, *TD)))
return NoAlias;
if (O1 != O2) {
if ((isa<CallInst>(O1) || isa<InvokeInst>(O1) || isa<LoadInst>(O1) ||
isa<Argument>(O1)) &&
isNonEscapingLocalObject(O2))
return NoAlias;
if ((isa<CallInst>(O2) || isa<InvokeInst>(O2) || isa<LoadInst>(O2) ||
isa<Argument>(O2)) &&
isNonEscapingLocalObject(O1))
return NoAlias;
}
if (!isa<GEPOperator>(V1) && isa<GEPOperator>(V2)) {
std::swap(V1, V2);
std::swap(V1Size, V2Size);
std::swap(O1, O2);
}
if (const GEPOperator *GV1 = dyn_cast<GEPOperator>(V1))
return aliasGEP(GV1, V1Size, V2, V2Size, O1, O2);
if (isa<PHINode>(V2) && !isa<PHINode>(V1)) {
std::swap(V1, V2);
std::swap(V1Size, V2Size);
}
if (const PHINode *PN = dyn_cast<PHINode>(V1))
return aliasPHI(PN, V1Size, V2, V2Size);
if (isa<SelectInst>(V2) && !isa<SelectInst>(V1)) {
std::swap(V1, V2);
std::swap(V1Size, V2Size);
}
if (const SelectInst *S1 = dyn_cast<SelectInst>(V1))
return aliasSelect(S1, V1Size, V2, V2Size);
return MayAlias;
}
DEFINING_FILE_FOR(BasicAliasAnalysis)