# HG changeset patch # User Frits van Bommel # Date 1241618295 -7200 # Node ID b61db48127fd18fce7618281c0cbc16bcfcf98b3 # Parent 8215dbf0e09f494e5a3faed191118443abae72d9 Some refactoring diff -r 8215dbf0e09f -r b61db48127fd gen/passes/GarbageCollect2Stack.cpp --- a/gen/passes/GarbageCollect2Stack.cpp Wed May 06 14:11:37 2009 +0200 +++ b/gen/passes/GarbageCollect2Stack.cpp Wed May 06 15:58:15 2009 +0200 @@ -47,14 +47,102 @@ //===----------------------------------------------------------------------===// namespace { - struct FunctionInfo { + struct Analysis { + TargetData& TD; + const Module& M; + + const Type* getTypeFor(Value* typeinfo) const; + }; + + class FunctionInfo { + protected: + const Type* Ty; + + public: unsigned TypeInfoArgNr; - int ArrSizeArgNr; bool SafeToDelete; - FunctionInfo(unsigned typeInfoArgNr, int arrSizeArgNr, bool safeToDelete) - : TypeInfoArgNr(typeInfoArgNr), ArrSizeArgNr(arrSizeArgNr), - SafeToDelete(safeToDelete) {} + // Analyze the current call, filling in some fields. Returns true if + // this is an allocation we can stack-allocate. + virtual bool analyze(CallSite CS, const Analysis& A) { + Value* TypeInfo = CS.getArgument(TypeInfoArgNr); + Ty = A.getTypeFor(TypeInfo); + return (Ty != NULL); + } + + // Returns the alloca to replace this call. + // It will always be inserted before the call. + virtual AllocaInst* promote(CallSite CS) { + NumGcToStack++; + + Instruction* Begin = CS.getCaller()->getEntryBlock().begin(); + return new AllocaInst(Ty, ".nongc_mem", Begin); + } + + FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete) + : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {} + }; + + class ArrayFI : public FunctionInfo { + Value* arrSize; + int ArrSizeArgNr; + + public: + ArrayFI(unsigned tiArgNr, bool safeToDelete, unsigned arrSizeArgNr) + : FunctionInfo(tiArgNr, safeToDelete), ArrSizeArgNr(arrSizeArgNr) {} + + virtual bool analyze(CallSite CS, const Analysis& A) { + if (!FunctionInfo::analyze(CS, A)) + return false; + + arrSize = CS.getArgument(ArrSizeArgNr); + const IntegerType* SizeType = + dyn_cast(arrSize->getType()); + if (!SizeType) + return false; + unsigned bits = SizeType->getBitWidth(); + if (bits > 32) { + // The array size of an alloca must be an i32, so make sure + // the conversion is safe. + APInt Mask = APInt::getHighBitsSet(bits, bits - 32); + APInt KnownZero(bits, 0), KnownOne(bits, 0); + ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &A.TD); + if ((KnownZero & Mask) != Mask) + return false; + } + // Extract the element type from the array type. + const StructType* ArrTy = dyn_cast(Ty); + assert(ArrTy && "Dynamic array type not a struct?"); + assert(isa(ArrTy->getElementType(0))); + const PointerType* PtrTy = + cast(ArrTy->getElementType(1)); + Ty = PtrTy->getElementType(); + return true; + } + + virtual AllocaInst* promote(CallSite CS) { + Instruction* I = CS.getInstruction(); + IRBuilder<> Builder(I->getParent(), I); + + // If the allocation is of constant size it's best to put it in the + // entry block, so do so if we're not already there. + // For dynamically-sized allocations it's best to avoid the overhead + // of allocating them if possible, so leave those where they are. + // While we're at it, update statistics too. + if (isa(arrSize)) { + BasicBlock& Entry = CS.getCaller()->getEntryBlock(); + if (Builder.GetInsertBlock() != &Entry) + Builder.SetInsertPoint(&Entry, Entry.begin()); + NumGcToStack++; + } else { + NumToDynSize++; + } + + // Convert array size to 32 bits if necessary + arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); + + return Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); + } }; /// This pass replaces GC calls with alloca's @@ -63,11 +151,16 @@ StringMap KnownFunctions; Module* M; - public: + FunctionInfo AllocMemoryT; + ArrayFI NewArrayVT; + + public: static char ID; // Pass identification - GarbageCollect2Stack() : FunctionPass(&ID) {} + GarbageCollect2Stack(); - bool doInitialization(Module &M); + bool doInitialization(Module &M) { + this->M = &M; + } bool runOnFunction(Function &F); @@ -75,9 +168,6 @@ AU.addRequired(); AU.addRequired(); } - - private: - const Type* getTypeFor(Value* typeinfo); }; char GarbageCollect2Stack::ID = 0; } // end anonymous namespace. @@ -90,10 +180,13 @@ return new GarbageCollect2Stack(); } -bool GarbageCollect2Stack::doInitialization(Module &M) { - this->M = &M; - KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, -1, true); - KnownFunctions["_d_newarrayvT"] = new FunctionInfo(0, 1, true); +GarbageCollect2Stack::GarbageCollect2Stack() +: FunctionPass(&ID), + AllocMemoryT(0, true), + NewArrayVT(0, true, 1) +{ + KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; + KnownFunctions["_d_newarrayvT"] = &NewArrayVT; } static void RemoveCall(Instruction* Inst) { @@ -119,6 +212,8 @@ TargetData &TD = getAnalysis(); const LoopInfo &LI = getAnalysis(); + Analysis A = { TD, *M }; + BasicBlock& Entry = F.getEntryBlock(); IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); @@ -167,70 +262,18 @@ DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); - Value* TypeInfo = CS.getArgument(info->TypeInfoArgNr); - const Type* Ty = getTypeFor(TypeInfo); - if (!Ty) { + if (!info->analyze(CS, A) || PointerMayBeCaptured(Inst, true)) continue; - } - - Value* arrSize = 0; - if (info->ArrSizeArgNr != -1) { - arrSize = CS.getArgument(info->ArrSizeArgNr); - const IntegerType* SizeType = - dyn_cast(arrSize->getType()); - if (!SizeType) - continue; - unsigned bits = SizeType->getBitWidth(); - if (bits > 32) { - // The array size of an alloca must be an i32, so make sure - // the conversion is safe. - APInt Mask = APInt::getHighBitsSet(bits, bits - 32); - APInt KnownZero(bits, 0), KnownOne(bits, 0); - ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &TD); - if ((KnownZero & Mask) != Mask) - continue; - } - // Extract the element type from the array type. - const StructType* ArrTy = dyn_cast(Ty); - assert(ArrTy && "Dynamic array type not a struct?"); - assert(isa(ArrTy->getElementType(0))); - const PointerType* PtrTy = - cast(ArrTy->getElementType(1)); - Ty = PtrTy->getElementType(); - } - - if (PointerMayBeCaptured(Inst, true)) { - continue; - } // Let's alloca this! Changed = true; - IRBuilder<> Builder(BB, I); - - // If the allocation is of constant size it's best to put it in the - // entry block, so do so if we're not already there. - // For dynamically-sized allocations it's best to avoid the overhead - // of allocating them if possible, so leave those where they are. - // While we're at it, update statistics too. - if (!arrSize || isa(arrSize)) { - if (&*BB != &Entry) - Builder = AllocaBuilder; - NumGcToStack++; - } else { - NumToDynSize++; - } - - // Convert array size to 32 bits if necessary - if (arrSize) - arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); - - Value* newVal = Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); + Value* newVal = info->promote(CS); // Make sure the type is the same as it was before, and replace all // uses of the runtime call with the alloca. if (newVal->getType() != Inst->getType()) - newVal = Builder.CreateBitCast(newVal, Inst->getType()); + newVal = new BitCastInst(newVal, Inst->getType(), "", Inst); Inst->replaceAllUsesWith(newVal); RemoveCall(Inst); @@ -240,7 +283,7 @@ return Changed; } -const Type* GarbageCollect2Stack::getTypeFor(Value* typeinfo) { +const Type* Analysis::getTypeFor(Value* typeinfo) const { GlobalVariable* ti_global = dyn_cast(typeinfo->stripPointerCasts()); if (!ti_global) return NULL; @@ -248,7 +291,7 @@ std::string metaname = TD_PREFIX; metaname.append(ti_global->getNameStart(), ti_global->getNameEnd()); - GlobalVariable* global = M->getGlobalVariable(metaname); + GlobalVariable* global = M.getGlobalVariable(metaname); if (!global || !global->hasInitializer()) return NULL;