summaryrefslogtreecommitdiff
path: root/lib/Analysis/MemoryBuiltins.cpp
blob: 2ca004edf9550ba4f0aae69e135657a8dbbbb71b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
//===------ MemoryBuiltins.cpp - Identify calls to memory builtins --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This family of functions identifies calls to builtin functions that allocate
// or free memory.  
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Analysis/ConstantFolding.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
//  malloc Call Utility Functions.
//

/// isMalloc - Returns true if the the value is either a malloc call or a
/// bitcast of the result of a malloc call.
bool llvm::isMalloc(const Value *I) {
  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
}

static bool isMallocCall(const CallInst *CI) {
  if (!CI)
    return false;

  Function *Callee = CI->getCalledFunction();
  if (Callee == 0 || !Callee->isDeclaration() || Callee->getName() != "malloc")
    return false;

  // Check malloc prototype.
  // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin 
  // attribute will exist.
  const FunctionType *FTy = Callee->getFunctionType();
  if (FTy->getNumParams() != 1)
    return false;
  if (IntegerType *ITy = dyn_cast<IntegerType>(FTy->param_begin()->get())) {
    if (ITy->getBitWidth() != 32 && ITy->getBitWidth() != 64)
      return false;
    return true;
  }

  return false;
}

/// extractMallocCall - Returns the corresponding CallInst if the instruction
/// is a malloc call.  Since CallInst::CreateMalloc() only creates calls, we
/// ignore InvokeInst here.
const CallInst *llvm::extractMallocCall(const Value *I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

CallInst *llvm::extractMallocCall(Value *I) {
  CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

static bool isBitCastOfMallocCall(const BitCastInst *BCI) {
  if (!BCI)
    return false;
    
  return isMallocCall(dyn_cast<CallInst>(BCI->getOperand(0)));
}

/// extractMallocCallFromBitCast - Returns the corresponding CallInst if the
/// instruction is a bitcast of the result of a malloc call.
CallInst *llvm::extractMallocCallFromBitCast(Value *I) {
  BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0))
                                      : NULL;
}

const CallInst *llvm::extractMallocCallFromBitCast(const Value *I) {
  const BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0))
                                      : NULL;
}

/// isConstantOne - Return true only if val is constant int 1.
static bool isConstantOne(Value *val) {
  return isa<ConstantInt>(val) && cast<ConstantInt>(val)->isOne();
}

static Value *isArrayMallocHelper(const CallInst *CI, const TargetData *TD) {
  if (!CI)
    return NULL;

  // Type must be known to determine array size.
  const Type *T = getMallocAllocatedType(CI);
  if (!T)
    return NULL;

  Value *MallocArg = CI->getOperand(1);
  ConstantExpr *CO = dyn_cast<ConstantExpr>(MallocArg);
  BinaryOperator *BO = dyn_cast<BinaryOperator>(MallocArg);

  Constant *ElementSize = ConstantExpr::getSizeOf(T);
  ElementSize = ConstantExpr::getTruncOrBitCast(ElementSize, 
                                                MallocArg->getType());
  Constant *FoldedElementSize =
   ConstantFoldConstantExpression(cast<ConstantExpr>(ElementSize), TD);

  // First, check if CI is a non-array malloc.
  if (CO && ((CO == ElementSize) ||
             (FoldedElementSize && (CO == FoldedElementSize))))
    // Match CreateMalloc's use of constant 1 array-size for non-array mallocs.
    return ConstantInt::get(MallocArg->getType(), 1);

  // Second, check if CI is an array malloc whose array size can be determined.
  if (isConstantOne(ElementSize) || 
      (FoldedElementSize && isConstantOne(FoldedElementSize)))
    return MallocArg;

  if (!CO && !BO)
    return NULL;

  Value *Op0 = NULL;
  Value *Op1 = NULL;
  unsigned Opcode = 0;
  if (CO && ((CO->getOpcode() == Instruction::Mul) || 
             (CO->getOpcode() == Instruction::Shl))) {
    Op0 = CO->getOperand(0);
    Op1 = CO->getOperand(1);
    Opcode = CO->getOpcode();
  }
  if (BO && ((BO->getOpcode() == Instruction::Mul) || 
             (BO->getOpcode() == Instruction::Shl))) {
    Op0 = BO->getOperand(0);
    Op1 = BO->getOperand(1);
    Opcode = BO->getOpcode();
  }

  // Determine array size if malloc's argument is the product of a mul or shl.
  if (Op0) {
    if (Opcode == Instruction::Mul) {
      if ((Op1 == ElementSize) ||
          (FoldedElementSize && (Op1 == FoldedElementSize)))
        // ArraySize * ElementSize
        return Op0;
      if ((Op0 == ElementSize) ||
          (FoldedElementSize && (Op0 == FoldedElementSize)))
        // ElementSize * ArraySize
        return Op1;
    }
    if (Opcode == Instruction::Shl) {
      ConstantInt *Op1CI = dyn_cast<ConstantInt>(Op1);
      if (!Op1CI) return NULL;
      
      APInt Op1Int = Op1CI->getValue();
      uint64_t BitToSet = Op1Int.getLimitedValue(Op1Int.getBitWidth() - 1);
      Value *Op1Pow = ConstantInt::get(Op1CI->getContext(), 
                                  APInt(Op1Int.getBitWidth(), 0).set(BitToSet));
      if (Op0 == ElementSize || (FoldedElementSize && Op0 == FoldedElementSize))
        // ArraySize << log2(ElementSize)
        return Op1Pow;
      if (Op1Pow == ElementSize ||
          (FoldedElementSize && Op1Pow == FoldedElementSize))
        // ElementSize << log2(ArraySize)
        return Op0;
    }
  }

  // We could not determine the malloc array size from MallocArg.
  return NULL;
}

/// isArrayMalloc - Returns the corresponding CallInst if the instruction 
/// is a call to malloc whose array size can be determined and the array size
/// is not constant 1.  Otherwise, return NULL.
CallInst *llvm::isArrayMalloc(Value *I, const TargetData *TD) {
  CallInst *CI = extractMallocCall(I);
  Value *ArraySize = isArrayMallocHelper(CI, TD);

  if (ArraySize &&
      ArraySize != ConstantInt::get(CI->getOperand(1)->getType(), 1))
    return CI;

  // CI is a non-array malloc or we can't figure out that it is an array malloc.
  return NULL;
}

const CallInst *llvm::isArrayMalloc(const Value *I, const TargetData *TD) {
  const CallInst *CI = extractMallocCall(I);
  Value *ArraySize = isArrayMallocHelper(CI, TD);

  if (ArraySize &&
      ArraySize != ConstantInt::get(CI->getOperand(1)->getType(), 1))
    return CI;

  // CI is a non-array malloc or we can't figure out that it is an array malloc.
  return NULL;
}

/// getMallocType - Returns the PointerType resulting from the malloc call.
/// This PointerType is the result type of the call's only bitcast use.
/// If there is no unique bitcast use, then return NULL.
const PointerType *llvm::getMallocType(const CallInst *CI) {
  assert(isMalloc(CI) && "GetMallocType and not malloc call");
  
  const BitCastInst *BCI = NULL;
  
  // Determine if CallInst has a bitcast use.
  for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end();
       UI != E; )
    if ((BCI = dyn_cast<BitCastInst>(cast<Instruction>(*UI++))))
      break;

  // Malloc call has 1 bitcast use and no other uses, so type is the bitcast's
  // destination type.
  if (BCI && CI->hasOneUse())
    return cast<PointerType>(BCI->getDestTy());

  // Malloc call was not bitcast, so type is the malloc function's return type.
  if (!BCI)
    return cast<PointerType>(CI->getType());

  // Type could not be determined.
  return NULL;
}

/// getMallocAllocatedType - Returns the Type allocated by malloc call. This
/// Type is the result type of the call's only bitcast use. If there is no
/// unique bitcast use, then return NULL.
const Type *llvm::getMallocAllocatedType(const CallInst *CI) {
  const PointerType *PT = getMallocType(CI);
  return PT ? PT->getElementType() : NULL;
}

/// getMallocArraySize - Returns the array size of a malloc call.  If the 
/// argument passed to malloc is a multiple of the size of the malloced type,
/// then return that multiple.  For non-array mallocs, the multiple is
/// constant 1.  Otherwise, return NULL for mallocs whose array size cannot be
/// determined.
Value *llvm::getMallocArraySize(CallInst *CI, const TargetData *TD) {
  return isArrayMallocHelper(CI, TD);
}

//===----------------------------------------------------------------------===//
//  free Call Utility Functions.
//

/// isFreeCall - Returns true if the the value is a call to the builtin free()
bool llvm::isFreeCall(const Value *I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  if (!CI)
    return false;
  Function *Callee = CI->getCalledFunction();
  if (Callee == 0 || !Callee->isDeclaration() || Callee->getName() != "free")
    return false;

  // Check free prototype.
  // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin 
  // attribute will exist.
  const FunctionType *FTy = Callee->getFunctionType();
  if (!FTy->getReturnType()->isVoidTy())
    return false;
  if (FTy->getNumParams() != 1)
    return false;
  if (FTy->param_begin()->get() != Type::getInt8PtrTy(Callee->getContext()))
    return false;

  return true;
}