# HG changeset patch # User Frits van Bommel # Date 1241634468 -7200 # Node ID e2ec50329af1d6e67c152b9dd98e84182f115200 # Parent b61db48127fd18fce7618281c0cbc16bcfcf98b3 Stack-allocate zero-initialized arrays. diff -r b61db48127fd -r e2ec50329af1 gen/passes/GarbageCollect2Stack.cpp --- a/gen/passes/GarbageCollect2Stack.cpp Wed May 06 15:58:15 2009 +0200 +++ b/gen/passes/GarbageCollect2Stack.cpp Wed May 06 20:27:48 2009 +0200 @@ -25,6 +25,7 @@ #include "llvm/Pass.h" #include "llvm/Module.h" +#include "llvm/Intrinsics.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/IRBuilder.h" @@ -43,7 +44,28 @@ STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); //===----------------------------------------------------------------------===// -// GarbageCollect2Stack Pass Implementation +// Helper functions +//===----------------------------------------------------------------------===// + +void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len) { + Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); + + Module *M = B.GetInsertBlock()->getParent()->getParent(); + const Type* Tys[1]; + Tys[0] = Len->getType(); + Value *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); + Value *Align = ConstantInt::get(Type::Int32Ty, 1); + + B.CreateCall4(MemSet, Dst, Val, Len, Align); +} + +static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) { + EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len); +} + + +//===----------------------------------------------------------------------===// +// Helpers for specific types of GC calls. //===----------------------------------------------------------------------===// namespace { @@ -72,7 +94,7 @@ // Returns the alloca to replace this call. // It will always be inserted before the call. - virtual AllocaInst* promote(CallSite CS) { + virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) { NumGcToStack++; Instruction* Begin = CS.getCaller()->getEntryBlock().begin(); @@ -86,10 +108,15 @@ class ArrayFI : public FunctionInfo { Value* arrSize; int ArrSizeArgNr; + bool Initialized; public: - ArrayFI(unsigned tiArgNr, bool safeToDelete, unsigned arrSizeArgNr) - : FunctionInfo(tiArgNr, safeToDelete), ArrSizeArgNr(arrSizeArgNr) {} + ArrayFI(unsigned tiArgNr, bool safeToDelete, bool initialized, + unsigned arrSizeArgNr) + : FunctionInfo(tiArgNr, safeToDelete), + ArrSizeArgNr(arrSizeArgNr), + Initialized(initialized) + {} virtual bool analyze(CallSite CS, const Analysis& A) { if (!FunctionInfo::analyze(CS, A)) @@ -120,10 +147,8 @@ return true; } - virtual AllocaInst* promote(CallSite CS) { - Instruction* I = CS.getInstruction(); - IRBuilder<> Builder(I->getParent(), I); - + virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) { + IRBuilder<> Builder = B; // 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 @@ -139,12 +164,30 @@ } // Convert array size to 32 bits if necessary - arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); + Value* count = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); + AllocaInst* alloca = Builder.CreateAlloca(Ty, count, ".nongc_mem"); - return Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); + if (Initialized) { + // For now, only zero-init is supported. + uint64_t size = A.TD.getTypeStoreSize(Ty); + Value* TypeSize = ConstantInt::get(arrSize->getType(), size); + // Use the original B to put initialization at the + // allocation site. + Value* Size = B.CreateMul(TypeSize, arrSize); + EmitMemZero(B, alloca, Size); + } + + return alloca; } }; - +} + + +//===----------------------------------------------------------------------===// +// GarbageCollect2Stack Pass Implementation +//===----------------------------------------------------------------------===// + +namespace { /// This pass replaces GC calls with alloca's /// class VISIBILITY_HIDDEN GarbageCollect2Stack : public FunctionPass { @@ -153,6 +196,7 @@ FunctionInfo AllocMemoryT; ArrayFI NewArrayVT; + ArrayFI NewArrayT; public: static char ID; // Pass identification @@ -183,10 +227,12 @@ GarbageCollect2Stack::GarbageCollect2Stack() : FunctionPass(&ID), AllocMemoryT(0, true), - NewArrayVT(0, true, 1) + NewArrayVT(0, true, false, 1), + NewArrayT(0, true, true, 1) { KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; KnownFunctions["_d_newarrayvT"] = &NewArrayVT; + KnownFunctions["_d_newarrayT"] = &NewArrayT; } static void RemoveCall(Instruction* Inst) { @@ -268,12 +314,13 @@ // Let's alloca this! Changed = true; - Value* newVal = info->promote(CS); + IRBuilder<> Builder(BB, Inst); + Value* newVal = info->promote(CS, Builder, A); // 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 = new BitCastInst(newVal, Inst->getType(), "", Inst); + newVal = Builder.CreateBitCast(newVal, Inst->getType()); Inst->replaceAllUsesWith(newVal); RemoveCall(Inst);