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
|
//===- ChangeAllocations.cpp - Modify %malloc & %free calls -----------------=//
//
// This file defines two passes that convert malloc and free instructions to
// calls to and from %malloc & %free function calls. The LowerAllocations
// transformation is a target dependant tranformation because it depends on the
// size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/ConstantVals.h"
#include "llvm/Pass.h"
#include "TransformInternals.h"
using std::vector;
namespace {
// LowerAllocations - Turn malloc and free instructions into %malloc and %free
// calls.
//
class LowerAllocations : public BasicBlockPass {
Function *MallocFunc; // Functions in the module we are processing
Function *FreeFunc; // Initialized by doInitialization
const TargetData &DataLayout;
public:
inline LowerAllocations(const TargetData &TD) : DataLayout(TD) {
MallocFunc = FreeFunc = 0;
}
// doPassInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
bool doInitialization(Module *M);
// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool runOnBasicBlock(BasicBlock *BB);
};
// RaiseAllocations - Turn %malloc and %free calls into the appropriate
// instruction.
//
class RaiseAllocations : public BasicBlockPass {
Function *MallocFunc; // Functions in the module we are processing
Function *FreeFunc; // Initialized by doPassInitializationVirt
public:
inline RaiseAllocations() : MallocFunc(0), FreeFunc(0) {}
// doPassInitialization - For the raise allocations pass, this finds a
// declaration for malloc and free if they exist.
//
bool doInitialization(Module *M);
// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool runOnBasicBlock(BasicBlock *BB);
};
} // end anonymous namespace
// doInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
// This function is always successful.
//
bool LowerAllocations::doInitialization(Module *M) {
const FunctionType *MallocType =
FunctionType::get(PointerType::get(Type::SByteTy),
vector<const Type*>(1, Type::UIntTy), false);
const FunctionType *FreeType =
FunctionType::get(Type::VoidTy,
vector<const Type*>(1, PointerType::get(Type::SByteTy)),
false);
MallocFunc = M->getOrInsertFunction("malloc", MallocType);
FreeFunc = M->getOrInsertFunction("free" , FreeType);
return false;
}
// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool LowerAllocations::runOnBasicBlock(BasicBlock *BB) {
bool Changed = false;
assert(MallocFunc && FreeFunc && BB && "Pass not initialized!");
// Loop over all of the instructions, looking for malloc or free instructions
for (unsigned i = 0; i < BB->size(); ++i) {
BasicBlock::InstListType &BBIL = BB->getInstList();
if (MallocInst *MI = dyn_cast<MallocInst>(*(BBIL.begin()+i))) {
BBIL.remove(BBIL.begin()+i); // remove the malloc instr...
const Type *AllocTy =cast<PointerType>(MI->getType())->getElementType();
// Get the number of bytes to be allocated for one element of the
// requested type...
unsigned Size = DataLayout.getTypeSize(AllocTy);
// malloc(type) becomes sbyte *malloc(constint)
Value *MallocArg = ConstantUInt::get(Type::UIntTy, Size);
if (MI->getNumOperands() && Size == 1) {
MallocArg = MI->getOperand(0); // Operand * 1 = Operand
} else if (MI->getNumOperands()) {
// Multiply it by the array size if neccesary...
MallocArg = BinaryOperator::create(Instruction::Mul,MI->getOperand(0),
MallocArg);
BBIL.insert(BBIL.begin()+i++, cast<Instruction>(MallocArg));
}
// Create the call to Malloc...
CallInst *MCall = new CallInst(MallocFunc,
vector<Value*>(1, MallocArg));
BBIL.insert(BBIL.begin()+i, MCall);
// Create a cast instruction to convert to the right type...
CastInst *MCast = new CastInst(MCall, MI->getType());
BBIL.insert(BBIL.begin()+i+1, MCast);
// Replace all uses of the old malloc inst with the cast inst
MI->replaceAllUsesWith(MCast);
delete MI; // Delete the malloc inst
Changed = true;
} else if (FreeInst *FI = dyn_cast<FreeInst>(*(BBIL.begin()+i))) {
BBIL.remove(BB->getInstList().begin()+i);
// Cast the argument to free into a ubyte*...
CastInst *MCast = new CastInst(FI->getOperand(0),
PointerType::get(Type::UByteTy));
BBIL.insert(BBIL.begin()+i, MCast);
// Insert a call to the free function...
CallInst *FCall = new CallInst(FreeFunc,
vector<Value*>(1, MCast));
BBIL.insert(BBIL.begin()+i+1, FCall);
// Delete the old free instruction
delete FI;
Changed = true;
}
}
return Changed;
}
bool RaiseAllocations::doInitialization(Module *M) {
// If the module has a symbol table, they might be referring to the malloc
// and free functions. If this is the case, grab the method pointers that
// the module is using.
//
// Lookup %malloc and %free in the symbol table, for later use. If they
// don't exist, or are not external, we do not worry about converting calls
// to that function into the appropriate instruction.
//
const FunctionType *MallocType = // Get the type for malloc
FunctionType::get(PointerType::get(Type::SByteTy),
vector<const Type*>(1, Type::UIntTy), false);
const FunctionType *FreeType = // Get the type for free
FunctionType::get(Type::VoidTy,
vector<const Type*>(1, PointerType::get(Type::SByteTy)),
false);
MallocFunc = M->getFunction("malloc", MallocType);
FreeFunc = M->getFunction("free" , FreeType);
// Don't mess with locally defined versions of these functions...
if (MallocFunc && !MallocFunc->isExternal()) MallocFunc = 0;
if (FreeFunc && !FreeFunc->isExternal()) FreeFunc = 0;
return false;
}
// doOneCleanupPass - Do one pass over the input method, fixing stuff up.
//
bool RaiseAllocations::runOnBasicBlock(BasicBlock *BB) {
bool Changed = false;
BasicBlock::InstListType &BIL = BB->getInstList();
for (BasicBlock::iterator BI = BB->begin(); BI != BB->end();) {
Instruction *I = *BI;
if (CallInst *CI = dyn_cast<CallInst>(I)) {
if (CI->getCalledValue() == MallocFunc) { // Replace call to malloc?
const Type *PtrSByte = PointerType::get(Type::SByteTy);
MallocInst *MallocI = new MallocInst(PtrSByte, CI->getOperand(1),
CI->getName());
CI->setName("");
ReplaceInstWithInst(BIL, BI, MallocI);
Changed = true;
continue; // Skip the ++BI
} else if (CI->getCalledValue() == FreeFunc) { // Replace call to free?
ReplaceInstWithInst(BIL, BI, new FreeInst(CI->getOperand(1)));
Changed = true;
continue; // Skip the ++BI
}
}
++BI;
}
return Changed;
}
Pass *createLowerAllocationsPass(const TargetData &TD) {
return new LowerAllocations(TD);
}
Pass *createRaiseAllocationsPass() {
return new RaiseAllocations();
}
|