Mercurial > projects > ldc
changeset 1297:8e8552601ecd
Stack promotion for _d_newarrayvT. Array literals, concatenations (a ~ b) and
such are eligible for stack-allocation now.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sun, 03 May 2009 18:01:45 +0200 |
parents | 79b201533cf8 |
children | 7e303f9f16c7 |
files | gen/passes/GarbageCollect2Stack.cpp |
diffstat | 1 files changed, 65 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/gen/passes/GarbageCollect2Stack.cpp Sun May 03 21:58:28 2009 +0200 +++ b/gen/passes/GarbageCollect2Stack.cpp Sun May 03 18:01:45 2009 +0200 @@ -29,6 +29,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/ADT/StringMap.h" @@ -37,7 +38,8 @@ #include "llvm/Support/Debug.h" using namespace llvm; -STATISTIC(NumGcToStack, "Number of GC calls promoted to stack allocations"); +STATISTIC(NumGcToStack, "Number of calls promoted to constant-size allocas"); +STATISTIC(NumToDynSize, "Number of calls promoted to dynamically-sized allocas"); STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); //===----------------------------------------------------------------------===// @@ -47,14 +49,12 @@ namespace { struct FunctionInfo { unsigned TypeInfoArgNr; + int ArrSizeArgNr; bool SafeToDelete; - FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete) - : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {} - - Value* getArraySize(CallSite CS) { - return 0; - } + FunctionInfo(unsigned typeInfoArgNr, int arrSizeArgNr, bool safeToDelete) + : TypeInfoArgNr(typeInfoArgNr), ArrSizeArgNr(arrSizeArgNr), + SafeToDelete(safeToDelete) {} }; /// This pass replaces GC calls with alloca's @@ -92,7 +92,8 @@ bool GarbageCollect2Stack::doInitialization(Module &M) { this->M = &M; - KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, true); + KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, -1, true); + KnownFunctions["_d_newarrayvT"] = new FunctionInfo(0, 1, true); } /// runOnFunction - Top level algorithm. @@ -100,7 +101,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) { DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); - const TargetData &TD = getAnalysis<TargetData>(); + TargetData &TD = getAnalysis<TargetData>(); const LoopInfo &LI = getAnalysis<LoopInfo>(); BasicBlock& Entry = F.getEntryBlock(); @@ -161,26 +162,76 @@ continue; } + Value* arrSize = 0; + if (info->ArrSizeArgNr != -1) { + arrSize = CS.getArgument(info->ArrSizeArgNr); + const IntegerType* SizeType = + dyn_cast<IntegerType>(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<StructType>(Ty); + assert(ArrTy && "Dynamic array type not a struct?"); + assert(isa<IntegerType>(ArrTy->getElementType(0))); + const PointerType* PtrTy = + cast<PointerType>(ArrTy->getElementType(1)); + Ty = PtrTy->getElementType(); + } + // Let's alloca this! Changed = true; - NumGcToStack++; + + IRBuilder<> Builder(BB, I); - Value* arrSize = info->getArraySize(CS); - Value* newVal = AllocaBuilder.CreateAlloca(Ty, arrSize, ".nongc_mem"); + // 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<Constant>(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"); + + // 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 = AllocaBuilder.CreateBitCast(newVal, Inst->getType()); - + newVal = Builder.CreateBitCast(newVal, Inst->getType()); Inst->replaceAllUsesWith(newVal); + // If this was an invoke instruction, update the control flow. if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) { + // Notify the exception landing pad block that we won't be + // going there anymore. Invoke->getUnwindDest()->removePredecessor(Invoke->getParent()); // Create a branch to the "normal" destination. BranchInst::Create(Invoke->getNormalDest(), Invoke->getParent()); } + + // Finally, remove the runtime call. Inst->eraseFromParent(); } } + return Changed; }