1
//===- PointerTracking.cpp - Pointer Bounds Tracking ------------*- C++ -*-===//
3
// The LLVM Compiler Infrastructure
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
8
//===----------------------------------------------------------------------===//
10
// This file implements tracking of pointer bounds.
12
//===----------------------------------------------------------------------===//
14
/* this shouldn't be part of win32 proj at all, but its easier to exclude here
18
#include "llvm/Analysis/ConstantFolding.h"
19
#include "llvm/Analysis/Dominators.h"
20
#include "llvm/Analysis/LoopInfo.h"
21
#include "llvm/Analysis/MemoryBuiltins.h"
22
#include "llvm/Analysis/ValueTracking.h"
23
#include "PointerTracking.h"
24
#include "llvm/Analysis/ScalarEvolution.h"
25
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
26
#include "llvm/Constants.h"
27
#include "llvm/Module.h"
28
#include "llvm/Value.h"
29
#include "llvm/Support/CallSite.h"
30
#include "llvm/Support/InstIterator.h"
31
#include "llvm/Support/raw_ostream.h"
32
#include "llvm/Target/TargetData.h"
35
void initializePointerTrackingPass(llvm::PassRegistry&);
37
INITIALIZE_PASS(PointerTracking, "pointertracking",
38
"Track pointer bounds", false, true);
39
char PointerTracking::ID = 0;
40
PointerTracking::PointerTracking() : FunctionPass(ID) {
41
initializePointerTrackingPass(*PassRegistry::getPassRegistry());
44
bool PointerTracking::runOnFunction(Function &F) {
46
assert(analyzing.empty());
48
TD = getAnalysisIfAvailable<TargetData>();
49
SE = &getAnalysis<ScalarEvolution>();
50
LI = &getAnalysis<LoopInfo>();
51
DT = &getAnalysis<DominatorTree>();
55
void PointerTracking::getAnalysisUsage(AnalysisUsage &AU) const {
56
AU.addRequiredTransitive<DominatorTree>();
57
AU.addRequiredTransitive<LoopInfo>();
58
AU.addRequiredTransitive<ScalarEvolution>();
62
bool PointerTracking::doInitialization(Module &M) {
63
const Type *PTy = Type::getInt8PtrTy(M.getContext());
65
// Find calloc(i64, i64) or calloc(i32, i32).
66
callocFunc = M.getFunction("calloc");
68
const FunctionType *Ty = callocFunc->getFunctionType();
70
std::vector<const Type*> args, args2;
71
args.push_back(Type::getInt64Ty(M.getContext()));
72
args.push_back(Type::getInt64Ty(M.getContext()));
73
args2.push_back(Type::getInt32Ty(M.getContext()));
74
args2.push_back(Type::getInt32Ty(M.getContext()));
75
const FunctionType *Calloc1Type =
76
FunctionType::get(PTy, args, false);
77
const FunctionType *Calloc2Type =
78
FunctionType::get(PTy, args2, false);
79
if (Ty != Calloc1Type && Ty != Calloc2Type)
80
callocFunc = 0; // Give up
83
// Find realloc(i8*, i64) or realloc(i8*, i32).
84
reallocFunc = M.getFunction("realloc");
86
const FunctionType *Ty = reallocFunc->getFunctionType();
87
std::vector<const Type*> args, args2;
89
args.push_back(Type::getInt64Ty(M.getContext()));
91
args2.push_back(Type::getInt32Ty(M.getContext()));
93
const FunctionType *Realloc1Type =
94
FunctionType::get(PTy, args, false);
95
const FunctionType *Realloc2Type =
96
FunctionType::get(PTy, args2, false);
97
if (Ty != Realloc1Type && Ty != Realloc2Type)
98
reallocFunc = 0; // Give up
103
// Calculates the number of elements allocated for pointer P,
104
// the type of the element is stored in Ty.
105
const SCEV *PointerTracking::computeAllocationCount(Value *P,
106
const Type *&Ty) const {
107
Value *V = P->stripPointerCasts();
108
if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
109
Value *arraySize = AI->getArraySize();
110
Ty = AI->getAllocatedType();
111
// arraySize elements of type Ty.
112
return SE->getSCEV(arraySize);
115
if (CallInst *CI = extractMallocCall(V)) {
116
Value *arraySize = getMallocArraySize(CI, TD);
117
const Type* AllocTy = getMallocAllocatedType(CI);
118
if (!AllocTy || !arraySize) return SE->getCouldNotCompute();
120
// arraySize elements of type Ty.
121
return SE->getSCEV(arraySize);
124
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
125
if (GV->hasDefinitiveInitializer()) {
126
Constant *C = GV->getInitializer();
127
if (const ArrayType *ATy = dyn_cast<ArrayType>(C->getType())) {
128
Ty = ATy->getElementType();
129
return SE->getConstant(Type::getInt32Ty(P->getContext()),
130
ATy->getNumElements());
134
return SE->getConstant(Type::getInt32Ty(P->getContext()), 1);
135
//TODO: implement more tracking for globals
138
if (CallInst *CI = dyn_cast<CallInst>(V)) {
140
Function *F = dyn_cast<Function>(CS.getCalledValue()->stripPointerCasts());
141
const Loop *L = LI->getLoopFor(CI->getParent());
142
if (F == callocFunc) {
143
Ty = Type::getInt8Ty(P->getContext());
144
// calloc allocates arg0*arg1 bytes.
145
return SE->getSCEVAtScope(SE->getMulExpr(SE->getSCEV(CS.getArgument(0)),
146
SE->getSCEV(CS.getArgument(1))),
148
} else if (F == reallocFunc) {
149
Ty = Type::getInt8Ty(P->getContext());
150
// realloc allocates arg1 bytes.
151
return SE->getSCEVAtScope(CS.getArgument(1), L);
155
return SE->getCouldNotCompute();
158
Value *PointerTracking::computeAllocationCountValue(Value *P, const Type *&Ty) const
160
Value *V = P->stripPointerCasts();
161
if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
162
Ty = AI->getAllocatedType();
163
// arraySize elements of type Ty.
164
return AI->getArraySize();
167
if (CallInst *CI = extractMallocCall(V)) {
168
Ty = getMallocAllocatedType(CI);
171
Value *arraySize = getMallocArraySize(CI, TD);
173
Ty = Type::getInt8Ty(P->getContext());
174
return CI->getArgOperand(0);
176
// arraySize elements of type Ty.
180
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
181
if (GV->hasDefinitiveInitializer()) {
182
Constant *C = GV->getInitializer();
183
if (const ArrayType *ATy = dyn_cast<ArrayType>(C->getType())) {
184
Ty = ATy->getElementType();
185
return ConstantInt::get(Type::getInt32Ty(P->getContext()),
186
ATy->getNumElements());
189
Ty = cast<PointerType>(GV->getType())->getElementType();
190
return ConstantInt::get(Type::getInt32Ty(P->getContext()), 1);
191
//TODO: implement more tracking for globals
194
if (CallInst *CI = dyn_cast<CallInst>(V)) {
196
Function *F = dyn_cast<Function>(CS.getCalledValue()->stripPointerCasts());
197
if (F == reallocFunc) {
198
Ty = Type::getInt8Ty(P->getContext());
199
// realloc allocates arg1 bytes.
200
return CS.getArgument(1);
207
// Calculates the number of elements of type Ty allocated for P.
208
const SCEV *PointerTracking::computeAllocationCountForType(Value *P,
211
const Type *elementTy;
212
const SCEV *Count = computeAllocationCount(P, elementTy);
213
if (isa<SCEVCouldNotCompute>(Count))
218
if (!TD) // need TargetData from this point forward
219
return SE->getCouldNotCompute();
221
uint64_t elementSize = TD->getTypeAllocSize(elementTy);
222
uint64_t wantSize = TD->getTypeAllocSize(Ty);
223
if (elementSize == wantSize)
225
if (elementSize % wantSize) //fractional counts not possible
226
return SE->getCouldNotCompute();
227
return SE->getMulExpr(Count, SE->getConstant(Count->getType(),
228
elementSize/wantSize));
231
const SCEV *PointerTracking::getAllocationElementCount(Value *V) const {
232
// We only deal with pointers.
233
const PointerType *PTy = cast<PointerType>(V->getType());
234
return computeAllocationCountForType(V, PTy->getElementType());
237
const SCEV *PointerTracking::getAllocationSizeInBytes(Value *V) const {
238
return computeAllocationCountForType(V, Type::getInt8Ty(V->getContext()));
241
// Helper for isLoopGuardedBy that checks the swapped and inverted predicate too
242
enum SolverResult PointerTracking::isLoopGuardedBy(const Loop *L,
245
const SCEV *B) const {
246
if (SE->isLoopEntryGuardedByCond(L, Pred, A, B))
248
Pred = ICmpInst::getSwappedPredicate(Pred);
249
if (SE->isLoopEntryGuardedByCond(L, Pred, B, A))
252
Pred = ICmpInst::getInversePredicate(Pred);
253
if (SE->isLoopEntryGuardedByCond(L, Pred, B, A))
255
Pred = ICmpInst::getSwappedPredicate(Pred);
256
if (SE->isLoopEntryGuardedByCond(L, Pred, A, B))
261
enum SolverResult PointerTracking::checkLimits(const SCEV *Offset,
265
//FIXME: merge implementation
269
void PointerTracking::getPointerOffset(Value *Pointer, Value *&Base,
271
const SCEV *&Offset) const
273
Pointer = Pointer->stripPointerCasts();
274
Base = GetUnderlyingObject(Pointer, TD);
275
Limit = getAllocationSizeInBytes(Base);
276
if (isa<SCEVCouldNotCompute>(Limit)) {
282
Offset = SE->getMinusSCEV(SE->getSCEV(Pointer), SE->getSCEV(Base));
283
if (isa<SCEVCouldNotCompute>(Offset)) {
289
void PointerTracking::print(raw_ostream &OS, const Module* M) const {
290
// Calling some PT methods may cause caches to be updated, however
291
// this should be safe for the same reason its safe for SCEV.
292
PointerTracking &PT = *const_cast<PointerTracking*>(this);
293
for (inst_iterator I=inst_begin(*FF), E=inst_end(*FF); I != E; ++I) {
294
if (!I->getType()->isPointerTy())
297
const SCEV *Limit, *Offset;
298
getPointerOffset(&*I, Base, Limit, Offset);
303
const SCEV *S = getAllocationElementCount(Base);
304
OS << *Base << " ==> " << *S << " elements, ";
305
OS << *Limit << " bytes allocated\n";
308
OS << &*I << " -- base: " << *Base;
309
OS << " offset: " << *Offset;
311
enum SolverResult res = PT.checkLimits(Offset, Limit, I->getParent());
314
OS << " always safe\n";
317
OS << " always unsafe\n";
320
OS << " <<unknown>>\n";