diff --git a/gen/functions.cpp b/gen/functions.cpp index 0c1bd292..6425c38c 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -772,6 +772,9 @@ void DtoDefineFunction(FuncDeclaration* fd) } #endif + FuncGen fg; + irfunction->gen = &fg; + DtoCreateNestedContext(fd); #if DMDV2 @@ -801,12 +804,8 @@ void DtoDefineFunction(FuncDeclaration* fd) } // output function body - { - FuncGen fg; - irfunction->gen = &fg; - fd->fbody->toIR(gIR); - irfunction->gen = 0; - } + fd->fbody->toIR(gIR); + irfunction->gen = 0; // TODO: clean up this mess diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 02aafeb6..ea7b553d 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -130,6 +130,17 @@ llvm::AllocaInst* DtoRawAlloca(const llvm::Type* lltype, size_t alignment, const return ai; } +LLValue* DtoGcMalloc(const llvm::Type* lltype, const char* name) +{ + // get runtime function + llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocmemory"); + // parameters + LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype)); + // call runtime allocator + LLValue* mem = gIR->CreateCallOrInvoke(fn, size, name).getInstruction(); + // cast + return DtoBitCast(mem, getPtrToType(lltype), name); +} /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 0aaa92d1..6d949aa9 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -45,6 +45,7 @@ void DtoDeleteArray(DValue* arr); llvm::AllocaInst* DtoAlloca(Type* type, const char* name = ""); llvm::AllocaInst* DtoArrayAlloca(Type* type, unsigned arraysize, const char* name = ""); llvm::AllocaInst* DtoRawAlloca(const llvm::Type* lltype, size_t alignment, const char* name = ""); +LLValue* DtoGcMalloc(const llvm::Type* lltype, const char* name = ""); // assertion generator void DtoAssert(Module* M, Loc loc, DValue* msg); diff --git a/gen/nested.cpp b/gen/nested.cpp index cd024e85..2366cc5b 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -68,6 +68,24 @@ static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) { return (parent ? parent->isFuncDeclaration() : NULL); } +static void storeVariable(VarDeclaration *vd, LLValue *dst) +{ + LLValue *value = vd->ir.irLocal->value; +#if DMDV2 + int ty = vd->type->ty; + FuncDeclaration *fd = getParentFunc(vd, true); + assert(fd && "No parent function for nested variable?"); + if (fd->needsClosure() && !vd->isRef() && (ty == Tstruct || ty == Tsarray) && isaPointer(value->getType())) { + // Copy structs and static arrays + LLValue *mem = DtoGcMalloc(DtoType(vd->type), ".gc_mem"); + DtoAggrCopy(mem, value); + DtoAlignedStore(mem, dst); + } else +#endif + // Store the address into the frame + DtoAlignedStore(value, dst); +} + static void DtoCreateNestedContextType(FuncDeclaration* fd); DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) @@ -206,7 +224,7 @@ void DtoNestedInit(VarDeclaration* vd) val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); } val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - DtoAlignedStore(vd->ir.irLocal->value, val); + storeVariable(vd, val); } else { // Already initialized in DtoCreateNestedContext } @@ -534,11 +552,15 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { unsigned depth = irfunction->depth; const llvm::StructType *frameType = irfunction->frameType; // Create frame for current function and append to frames list - // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca - // (Note that it'd also require more aggressive copying of - // by-value parameters instead of just alloca'd ones) // FIXME: alignment ? - LLValue* frame = DtoRawAlloca(frameType, 0, ".frame"); + LLValue* frame = 0; +#if DMDV2 + if (fd->needsClosure()) + frame = DtoGcMalloc(frameType, ".frame"); + else +#endif + frame = DtoRawAlloca(frameType, 0, ".frame"); + // copy parent frames into beginning if (depth != 0) { @@ -602,7 +624,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { // passed-in pointer (for 'ref' or 'out' parameters) or // a pointer arg with byval attribute. // Store the address into the frame and set the byref flag. - DtoAlignedStore(vd->ir.irLocal->value, gep); + storeVariable(vd, gep); vd->ir.irLocal->byref = true; } } else if (vd->isRef() || vd->isOut()) { diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 30e3f350..7b7bfd99 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -264,6 +264,17 @@ static void LLVM_D_BuildRuntimeModule() ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// + + // void* _d_allocmemory(size_t sz) + { + llvm::StringRef fname("_d_allocmemory"); + std::vector types; + types.push_back(sizeTy); + const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false); + llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) + ->setAttributes(Attr_NoAlias); + } + // void* _d_allocmemoryT(TypeInfo ti) { llvm::StringRef fname("_d_allocmemoryT"); diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 7bffb3cc..8f1ec314 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -778,6 +778,11 @@ size_t getTypePaddedSize(const LLType* t) return sz; } +size_t getTypeAllocSize(const LLType* t) +{ + return gTargetData->getTypeAllocSize(t); +} + unsigned char getABITypeAlign(const LLType* t) { return gTargetData->getABITypeAlignment(t); diff --git a/gen/tollvm.h b/gen/tollvm.h index 575bb981..76d543ec 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -95,6 +95,7 @@ LLConstant* getNullValue(const LLType* t); size_t getTypeBitSize(const LLType* t); size_t getTypeStoreSize(const LLType* t); size_t getTypePaddedSize(const LLType* t); +size_t getTypeAllocSize(const LLType* t); // type alignments unsigned char getABITypeAlign(const LLType* t);