From 9f1c26b52a310266bdaa6bc916eb7806ea1a1b33 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 27 Oct 2013 16:42:04 +0100 Subject: [PATCH] gc2stack: Handle _d_allocmemory. This allows us to clean up after inlining closures. --- gen/passes/GarbageCollect2Stack.cpp | 61 ++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index 45b5dd29..901f1dc2 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -302,6 +302,62 @@ namespace { AllocClassFI() : FunctionInfo(ReturnType::Pointer) {} }; + + /// Describes runtime functions that allocate a chunk of memory with a + /// given size. + class UntypedMemoryFI : public FunctionInfo { + unsigned SizeArgNr; + Value* SizeArg; + public: + virtual bool analyze(CallSite CS, const Analysis& A) { + if (CS.arg_size() < SizeArgNr + 1) + return false; + + SizeArg = CS.getArgument(SizeArgNr); + + // If the user explicitly disabled the limits, don't even check + // whether the allocated size fits in 32 bits. This could cause + // miscompilations for humongous allocations, but as the value + // "range" (set bits) inference algorithm is rather limited, this + // is useful for experimenting. + if (SizeLimit > 0) { + if (!isKnownLessThan(SizeArg, SizeLimit, A)) + return false; + } + + // Should be i8. + Ty = CS.getType()->getContainedType(0); + return true; + } + + virtual Value* 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 + // of allocating them if possible, so leave those where they are. + // While we're at it, update statistics too. + if (isa(SizeArg)) { + 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 + Value* count = Builder.CreateIntCast(SizeArg, Builder.getInt32Ty(), false); + AllocaInst* alloca = Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align? + + return Builder.CreateBitCast(alloca, CS.getType()); + } + + UntypedMemoryFI(unsigned sizeArgNr) + : FunctionInfo(ReturnType::Pointer), + SizeArgNr(sizeArgNr) + {} + }; } @@ -320,6 +376,7 @@ namespace { ArrayFI NewArrayVT; ArrayFI NewArrayT; AllocClassFI AllocClass; + UntypedMemoryFI AllocMemory; public: static char ID; // Pass identification @@ -358,12 +415,14 @@ GarbageCollect2Stack::GarbageCollect2Stack() : FunctionPass(ID), AllocMemoryT(ReturnType::Pointer, 0), NewArrayVT(ReturnType::Array, 0, 1, false), - NewArrayT(ReturnType::Array, 0, 1, true) + NewArrayT(ReturnType::Array, 0, 1, true), + AllocMemory(0) { KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; KnownFunctions["_d_newarrayvT"] = &NewArrayVT; KnownFunctions["_d_newarrayT"] = &NewArrayT; KnownFunctions["_d_newclass"] = &AllocClass; + KnownFunctions["_d_allocmemory"] = &AllocMemory; } static void RemoveCall(CallSite CS, const Analysis& A) {