comparison gen/passes/GarbageCollect2Stack.cpp @ 1306:b61db48127fd

Some refactoring
author Frits van Bommel <fvbommel wxs.nl>
date Wed, 06 May 2009 15:58:15 +0200
parents 8215dbf0e09f
children e2ec50329af1
comparison
equal deleted inserted replaced
1305:8215dbf0e09f 1306:b61db48127fd
45 //===----------------------------------------------------------------------===// 45 //===----------------------------------------------------------------------===//
46 // GarbageCollect2Stack Pass Implementation 46 // GarbageCollect2Stack Pass Implementation
47 //===----------------------------------------------------------------------===// 47 //===----------------------------------------------------------------------===//
48 48
49 namespace { 49 namespace {
50 struct FunctionInfo { 50 struct Analysis {
51 TargetData& TD;
52 const Module& M;
53
54 const Type* getTypeFor(Value* typeinfo) const;
55 };
56
57 class FunctionInfo {
58 protected:
59 const Type* Ty;
60
61 public:
51 unsigned TypeInfoArgNr; 62 unsigned TypeInfoArgNr;
63 bool SafeToDelete;
64
65 // Analyze the current call, filling in some fields. Returns true if
66 // this is an allocation we can stack-allocate.
67 virtual bool analyze(CallSite CS, const Analysis& A) {
68 Value* TypeInfo = CS.getArgument(TypeInfoArgNr);
69 Ty = A.getTypeFor(TypeInfo);
70 return (Ty != NULL);
71 }
72
73 // Returns the alloca to replace this call.
74 // It will always be inserted before the call.
75 virtual AllocaInst* promote(CallSite CS) {
76 NumGcToStack++;
77
78 Instruction* Begin = CS.getCaller()->getEntryBlock().begin();
79 return new AllocaInst(Ty, ".nongc_mem", Begin);
80 }
81
82 FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete)
83 : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {}
84 };
85
86 class ArrayFI : public FunctionInfo {
87 Value* arrSize;
52 int ArrSizeArgNr; 88 int ArrSizeArgNr;
53 bool SafeToDelete; 89
54 90 public:
55 FunctionInfo(unsigned typeInfoArgNr, int arrSizeArgNr, bool safeToDelete) 91 ArrayFI(unsigned tiArgNr, bool safeToDelete, unsigned arrSizeArgNr)
56 : TypeInfoArgNr(typeInfoArgNr), ArrSizeArgNr(arrSizeArgNr), 92 : FunctionInfo(tiArgNr, safeToDelete), ArrSizeArgNr(arrSizeArgNr) {}
57 SafeToDelete(safeToDelete) {} 93
94 virtual bool analyze(CallSite CS, const Analysis& A) {
95 if (!FunctionInfo::analyze(CS, A))
96 return false;
97
98 arrSize = CS.getArgument(ArrSizeArgNr);
99 const IntegerType* SizeType =
100 dyn_cast<IntegerType>(arrSize->getType());
101 if (!SizeType)
102 return false;
103 unsigned bits = SizeType->getBitWidth();
104 if (bits > 32) {
105 // The array size of an alloca must be an i32, so make sure
106 // the conversion is safe.
107 APInt Mask = APInt::getHighBitsSet(bits, bits - 32);
108 APInt KnownZero(bits, 0), KnownOne(bits, 0);
109 ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &A.TD);
110 if ((KnownZero & Mask) != Mask)
111 return false;
112 }
113 // Extract the element type from the array type.
114 const StructType* ArrTy = dyn_cast<StructType>(Ty);
115 assert(ArrTy && "Dynamic array type not a struct?");
116 assert(isa<IntegerType>(ArrTy->getElementType(0)));
117 const PointerType* PtrTy =
118 cast<PointerType>(ArrTy->getElementType(1));
119 Ty = PtrTy->getElementType();
120 return true;
121 }
122
123 virtual AllocaInst* promote(CallSite CS) {
124 Instruction* I = CS.getInstruction();
125 IRBuilder<> Builder(I->getParent(), I);
126
127 // If the allocation is of constant size it's best to put it in the
128 // entry block, so do so if we're not already there.
129 // For dynamically-sized allocations it's best to avoid the overhead
130 // of allocating them if possible, so leave those where they are.
131 // While we're at it, update statistics too.
132 if (isa<Constant>(arrSize)) {
133 BasicBlock& Entry = CS.getCaller()->getEntryBlock();
134 if (Builder.GetInsertBlock() != &Entry)
135 Builder.SetInsertPoint(&Entry, Entry.begin());
136 NumGcToStack++;
137 } else {
138 NumToDynSize++;
139 }
140
141 // Convert array size to 32 bits if necessary
142 arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false);
143
144 return Builder.CreateAlloca(Ty, arrSize, ".nongc_mem");
145 }
58 }; 146 };
59 147
60 /// This pass replaces GC calls with alloca's 148 /// This pass replaces GC calls with alloca's
61 /// 149 ///
62 class VISIBILITY_HIDDEN GarbageCollect2Stack : public FunctionPass { 150 class VISIBILITY_HIDDEN GarbageCollect2Stack : public FunctionPass {
63 StringMap<FunctionInfo*> KnownFunctions; 151 StringMap<FunctionInfo*> KnownFunctions;
64 Module* M; 152 Module* M;
65 153
66 public: 154 FunctionInfo AllocMemoryT;
155 ArrayFI NewArrayVT;
156
157 public:
67 static char ID; // Pass identification 158 static char ID; // Pass identification
68 GarbageCollect2Stack() : FunctionPass(&ID) {} 159 GarbageCollect2Stack();
69 160
70 bool doInitialization(Module &M); 161 bool doInitialization(Module &M) {
162 this->M = &M;
163 }
71 164
72 bool runOnFunction(Function &F); 165 bool runOnFunction(Function &F);
73 166
74 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 167 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
75 AU.addRequired<TargetData>(); 168 AU.addRequired<TargetData>();
76 AU.addRequired<LoopInfo>(); 169 AU.addRequired<LoopInfo>();
77 } 170 }
78
79 private:
80 const Type* getTypeFor(Value* typeinfo);
81 }; 171 };
82 char GarbageCollect2Stack::ID = 0; 172 char GarbageCollect2Stack::ID = 0;
83 } // end anonymous namespace. 173 } // end anonymous namespace.
84 174
85 static RegisterPass<GarbageCollect2Stack> 175 static RegisterPass<GarbageCollect2Stack>
88 // Public interface to the pass. 178 // Public interface to the pass.
89 FunctionPass *createGarbageCollect2Stack() { 179 FunctionPass *createGarbageCollect2Stack() {
90 return new GarbageCollect2Stack(); 180 return new GarbageCollect2Stack();
91 } 181 }
92 182
93 bool GarbageCollect2Stack::doInitialization(Module &M) { 183 GarbageCollect2Stack::GarbageCollect2Stack()
94 this->M = &M; 184 : FunctionPass(&ID),
95 KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, -1, true); 185 AllocMemoryT(0, true),
96 KnownFunctions["_d_newarrayvT"] = new FunctionInfo(0, 1, true); 186 NewArrayVT(0, true, 1)
187 {
188 KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT;
189 KnownFunctions["_d_newarrayvT"] = &NewArrayVT;
97 } 190 }
98 191
99 static void RemoveCall(Instruction* Inst) { 192 static void RemoveCall(Instruction* Inst) {
100 if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) { 193 if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) {
101 // If this was an invoke instruction, we need to do some extra 194 // If this was an invoke instruction, we need to do some extra
116 bool GarbageCollect2Stack::runOnFunction(Function &F) { 209 bool GarbageCollect2Stack::runOnFunction(Function &F) {
117 DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); 210 DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n');
118 211
119 TargetData &TD = getAnalysis<TargetData>(); 212 TargetData &TD = getAnalysis<TargetData>();
120 const LoopInfo &LI = getAnalysis<LoopInfo>(); 213 const LoopInfo &LI = getAnalysis<LoopInfo>();
214
215 Analysis A = { TD, *M };
121 216
122 BasicBlock& Entry = F.getEntryBlock(); 217 BasicBlock& Entry = F.getEntryBlock();
123 218
124 IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); 219 IRBuilder<> AllocaBuilder(&Entry, Entry.begin());
125 220
165 continue; 260 continue;
166 } 261 }
167 262
168 DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); 263 DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst);
169 264
170 Value* TypeInfo = CS.getArgument(info->TypeInfoArgNr); 265 if (!info->analyze(CS, A) || PointerMayBeCaptured(Inst, true))
171 const Type* Ty = getTypeFor(TypeInfo);
172 if (!Ty) {
173 continue; 266 continue;
174 }
175
176 Value* arrSize = 0;
177 if (info->ArrSizeArgNr != -1) {
178 arrSize = CS.getArgument(info->ArrSizeArgNr);
179 const IntegerType* SizeType =
180 dyn_cast<IntegerType>(arrSize->getType());
181 if (!SizeType)
182 continue;
183 unsigned bits = SizeType->getBitWidth();
184 if (bits > 32) {
185 // The array size of an alloca must be an i32, so make sure
186 // the conversion is safe.
187 APInt Mask = APInt::getHighBitsSet(bits, bits - 32);
188 APInt KnownZero(bits, 0), KnownOne(bits, 0);
189 ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &TD);
190 if ((KnownZero & Mask) != Mask)
191 continue;
192 }
193 // Extract the element type from the array type.
194 const StructType* ArrTy = dyn_cast<StructType>(Ty);
195 assert(ArrTy && "Dynamic array type not a struct?");
196 assert(isa<IntegerType>(ArrTy->getElementType(0)));
197 const PointerType* PtrTy =
198 cast<PointerType>(ArrTy->getElementType(1));
199 Ty = PtrTy->getElementType();
200 }
201
202 if (PointerMayBeCaptured(Inst, true)) {
203 continue;
204 }
205 267
206 // Let's alloca this! 268 // Let's alloca this!
207 Changed = true; 269 Changed = true;
208 270
209 IRBuilder<> Builder(BB, I); 271 Value* newVal = info->promote(CS);
210
211 // If the allocation is of constant size it's best to put it in the
212 // entry block, so do so if we're not already there.
213 // For dynamically-sized allocations it's best to avoid the overhead
214 // of allocating them if possible, so leave those where they are.
215 // While we're at it, update statistics too.
216 if (!arrSize || isa<Constant>(arrSize)) {
217 if (&*BB != &Entry)
218 Builder = AllocaBuilder;
219 NumGcToStack++;
220 } else {
221 NumToDynSize++;
222 }
223
224 // Convert array size to 32 bits if necessary
225 if (arrSize)
226 arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false);
227
228 Value* newVal = Builder.CreateAlloca(Ty, arrSize, ".nongc_mem");
229 272
230 // Make sure the type is the same as it was before, and replace all 273 // Make sure the type is the same as it was before, and replace all
231 // uses of the runtime call with the alloca. 274 // uses of the runtime call with the alloca.
232 if (newVal->getType() != Inst->getType()) 275 if (newVal->getType() != Inst->getType())
233 newVal = Builder.CreateBitCast(newVal, Inst->getType()); 276 newVal = new BitCastInst(newVal, Inst->getType(), "", Inst);
234 Inst->replaceAllUsesWith(newVal); 277 Inst->replaceAllUsesWith(newVal);
235 278
236 RemoveCall(Inst); 279 RemoveCall(Inst);
237 } 280 }
238 } 281 }
239 282
240 return Changed; 283 return Changed;
241 } 284 }
242 285
243 const Type* GarbageCollect2Stack::getTypeFor(Value* typeinfo) { 286 const Type* Analysis::getTypeFor(Value* typeinfo) const {
244 GlobalVariable* ti_global = dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts()); 287 GlobalVariable* ti_global = dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts());
245 if (!ti_global) 288 if (!ti_global)
246 return NULL; 289 return NULL;
247 290
248 std::string metaname = TD_PREFIX; 291 std::string metaname = TD_PREFIX;
249 metaname.append(ti_global->getNameStart(), ti_global->getNameEnd()); 292 metaname.append(ti_global->getNameStart(), ti_global->getNameEnd());
250 293
251 GlobalVariable* global = M->getGlobalVariable(metaname); 294 GlobalVariable* global = M.getGlobalVariable(metaname);
252 if (!global || !global->hasInitializer()) 295 if (!global || !global->hasInitializer())
253 return NULL; 296 return NULL;
254 297
255 MDNode* node = dyn_cast<MDNode>(global->getInitializer()); 298 MDNode* node = dyn_cast<MDNode>(global->getInitializer());
256 if (!node) 299 if (!node)