From 3eb6b5e8c88ed231c08cd26a9a2f0f25b9177fea Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Tue, 14 Dec 2010 14:35:52 +0300 Subject: [PATCH] Fixed a crash when compiling test runnable/A16. --- gen/functions.cpp | 12 +-- gen/llvmhelpers.cpp | 1 - gen/nested.cpp | 215 +++++++++++++++++++++++++++----------------- ir/irfunction.cpp | 1 + ir/irfunction.h | 1 + 5 files changed, 134 insertions(+), 96 deletions(-) diff --git a/gen/functions.cpp b/gen/functions.cpp index a6c84a29..0c1bd292 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -529,7 +529,7 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) #endif // we never reference parameters of function prototypes std::string str; - if (!declareOnly) + // if (!declareOnly) { // name parameters llvm::Function::arg_iterator iarg = func->arg_begin(); @@ -772,16 +772,6 @@ void DtoDefineFunction(FuncDeclaration* fd) } #endif -#if DMDV2 - // fill nestedVars - size_t nnest = fd->closureVars.dim; - for (size_t i = 0; i < nnest; ++i) - { - VarDeclaration* vd = (VarDeclaration*)fd->closureVars.data[i]; - fd->nestedVars.insert(vd); - } -#endif - DtoCreateNestedContext(fd); #if DMDV2 diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 4993eefa..02aafeb6 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -958,7 +958,6 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) #endif Logger::println("has nestedref set"); assert(vd->ir.irLocal); - DtoNestedInit(vd); } // normal stack variable, allocate storage on the stack if it has not already been done diff --git a/gen/nested.cpp b/gen/nested.cpp index 27a9d47d..cd024e85 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -68,6 +68,8 @@ static FuncDeclaration* getParentFunc(Dsymbol* sym, bool stopOnStatic) { return (parent ? parent->isFuncDeclaration() : NULL); } +static void DtoCreateNestedContextType(FuncDeclaration* fd); + DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) { Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars()); @@ -109,6 +111,7 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) ctx = irfunc->nestArg; assert(ctx); + DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(vd->ir.irLocal); //////////////////////////////////// @@ -270,14 +273,18 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) if (nestedCtx == NCHybrid) { if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { // Make sure we've had a chance to analyze nested context usage + #if DMDV2 + DtoCreateNestedContextType(symfd); + #else DtoDefineFunction(symfd); - + #endif + // if this is for a function that doesn't access variables from // enclosing scopes, it doesn't matter what we pass. // Tell LLVM about it by passing an 'undef'. if (symfd && symfd->ir.irFunc->depth == -1) return llvm::UndefValue::get(getVoidPtrType()); - + // If sym is a nested function, and it's parent context is different than the // one we got, adjust it. if (FuncDeclaration* fd = getParentFunc(symfd, true)) { @@ -289,13 +296,13 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) assert(ctxfd && "Context from outer function, but no outer function?"); } Logger::println("Context is from %s", ctxfd->toChars()); - + unsigned neededDepth = fd->ir.irFunc->depth; unsigned ctxDepth = ctxfd->ir.irFunc->depth; - + Logger::cout() << "Needed depth: " << neededDepth << '\n'; Logger::cout() << "Context depth: " << ctxDepth << '\n'; - + if (neededDepth >= ctxDepth) { // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); // fd needs the same context as we do, so all is well @@ -313,10 +320,125 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) return val; } +static void DtoCreateNestedContextType(FuncDeclaration* fd) { + Logger::println("DtoCreateNestedContextType for %s", fd->toChars()); + LOG_SCOPE + + if (fd->ir.irFunc->nestedContextCreated) + return; + fd->ir.irFunc->nestedContextCreated = true; + +#if DMDV2 + DtoDeclareFunction(fd); + if (fd->nestedVars.empty()) { + // fill nestedVars + size_t nnest = fd->closureVars.dim; + for (size_t i = 0; i < nnest; ++i) + { + VarDeclaration* vd = (VarDeclaration*)fd->closureVars.data[i]; + fd->nestedVars.insert(vd); + } + } +#endif + if (nestedCtx == NCHybrid) { + // construct nested variables array + if (!fd->nestedVars.empty()) + { + Logger::println("has nested frame"); + // start with adding all enclosing parent frames until a static parent is reached + + const LLStructType* innerFrameType = NULL; + unsigned depth = -1; + if (!fd->isStatic()) { + if (FuncDeclaration* parfd = getParentFunc(fd, true)) { + innerFrameType = parfd->ir.irFunc->frameType; + if (innerFrameType) + depth = parfd->ir.irFunc->depth; + } + } + fd->ir.irFunc->depth = ++depth; + + Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; + + typedef std::vector TypeVec; + TypeVec types; + if (depth != 0) { + assert(innerFrameType); + // Add frame pointer types for all but last frame + if (depth > 1) { + for (unsigned i = 0; i < (depth - 1); ++i) { + types.push_back(innerFrameType->getElementType(i)); + } + } + // Add frame pointer type for last frame + types.push_back(LLPointerType::getUnqual(innerFrameType)); + } + + if (Logger::enabled()) { + Logger::println("Frame types: "); + LOG_SCOPE; + for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) + Logger::cout() << **i << '\n'; + } + + // Add the direct nested variables of this function, and update their indices to match. + // TODO: optimize ordering for minimal space usage? + for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) + { + VarDeclaration* vd = *i; + if (!vd->ir.irLocal) + vd->ir.irLocal = new IrLocal(vd); + + vd->ir.irLocal->nestedIndex = types.size(); + vd->ir.irLocal->nestedDepth = depth; + if (vd->isParameter()) { + // Parameters already have storage associated with them (to handle byref etc.), + // so handle those cases specially by storing a pointer instead of a value. + assert(vd->ir.irLocal->value); + LLValue* value = vd->ir.irLocal->value; + const LLType* type = value->getType(); + if (llvm::isa(value->getUnderlyingObject())) + // This will be copied to the nesting frame. + type = type->getContainedType(0); + types.push_back(type); + } else if (vd->isRef() || vd->isOut()) { + // Foreach variables can also be by reference, for instance. + types.push_back(DtoType(vd->type->pointerTo())); + } else { + types.push_back(DtoType(vd->type)); + } + if (Logger::enabled()) { + Logger::println("Nested var: %s", vd->toChars()); + Logger::cout() << "of type: " << *types.back() << '\n'; + } + } + + const LLStructType* frameType = LLStructType::get(gIR->context(), types); + gIR->module->addTypeName(std::string("nest.") + fd->toChars(), frameType); + + Logger::cout() << "frameType = " << *frameType << '\n'; + + // Store type in IrFunction + fd->ir.irFunc->frameType = frameType; + } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { + // Propagate context arg properties if the context arg is passed on unmodified. + DtoCreateNestedContextType(parFunc); + fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; + fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; + } + } + else { + assert(0 && "Not implemented yet"); + } +} + + void DtoCreateNestedContext(FuncDeclaration* fd) { Logger::println("DtoCreateNestedContext for %s", fd->toChars()); LOG_SCOPE - + + DtoCreateNestedContextType(fd); + if (nestedCtx == NCArray) { // construct nested variables array if (!fd->nestedVars.empty()) @@ -408,84 +530,9 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { // construct nested variables array if (!fd->nestedVars.empty()) { - Logger::println("has nested frame"); - // start with adding all enclosing parent frames until a static parent is reached - - const LLStructType* innerFrameType = NULL; - unsigned depth = -1; - if (!fd->isStatic()) { - if (FuncDeclaration* parfd = getParentFunc(fd, true)) { - innerFrameType = parfd->ir.irFunc->frameType; - if (innerFrameType) - depth = parfd->ir.irFunc->depth; - } - } - fd->ir.irFunc->depth = ++depth; - - Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; - - typedef std::vector TypeVec; - TypeVec types; - if (depth != 0) { - assert(innerFrameType); - // Add frame pointer types for all but last frame - if (depth > 1) { - for (unsigned i = 0; i < (depth - 1); ++i) { - types.push_back(innerFrameType->getElementType(i)); - } - } - // Add frame pointer type for last frame - types.push_back(LLPointerType::getUnqual(innerFrameType)); - } - - if (Logger::enabled()) { - Logger::println("Frame types: "); - LOG_SCOPE; - for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) - Logger::cout() << **i << '\n'; - } - - // Add the direct nested variables of this function, and update their indices to match. - // TODO: optimize ordering for minimal space usage? - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); - - vd->ir.irLocal->nestedIndex = types.size(); - vd->ir.irLocal->nestedDepth = depth; - if (vd->isParameter()) { - // Parameters already have storage associated with them (to handle byref etc.), - // so handle those cases specially by storing a pointer instead of a value. - assert(vd->ir.irLocal->value); - LLValue* value = vd->ir.irLocal->value; - const LLType* type = value->getType(); - if (llvm::isa(value->getUnderlyingObject())) - // This will be copied to the nesting frame. - type = type->getContainedType(0); - types.push_back(type); - } else if (vd->isRef() || vd->isOut()) { - // Foreach variables can also be by reference, for instance. - types.push_back(DtoType(vd->type->pointerTo())); - } else { - types.push_back(DtoType(vd->type)); - } - if (Logger::enabled()) { - Logger::println("Nested var: %s", vd->toChars()); - Logger::cout() << "of type: " << *types.back() << '\n'; - } - } - - const LLStructType* frameType = LLStructType::get(gIR->context(), types); - gIR->module->addTypeName(std::string("nest.") + fd->toChars(), frameType); - - Logger::cout() << "frameType = " << *frameType << '\n'; - - // Store type in IrFunction IrFunction* irfunction = fd->ir.irFunc; - irfunction->frameType = frameType; - + 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 @@ -522,7 +569,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { getABITypeAlign(getVoidPtrType())); } // Copy nestArg into framelist; the outer frame is not in the list of pointers - src = DtoBitCast(src, types[depth-1]); + src = DtoBitCast(src, frameType->getContainedType(depth-1)); LLValue* gep = DtoGEPi(frame, 0, depth-1); DtoAlignedStore(src, gep); } diff --git a/ir/irfunction.cpp b/ir/irfunction.cpp index 415dad66..518c85eb 100644 --- a/ir/irfunction.cpp +++ b/ir/irfunction.cpp @@ -144,6 +144,7 @@ IrFunction::IrFunction(FuncDeclaration* fd) nestedVar = NULL; frameType = NULL; depth = -1; + nestedContextCreated = false; _arguments = NULL; _argptr = NULL; diff --git a/ir/irfunction.h b/ir/irfunction.h index 055233b2..2bc13243 100644 --- a/ir/irfunction.h +++ b/ir/irfunction.h @@ -93,6 +93,7 @@ struct IrFunction : IrBase // number of enclosing functions with variables accessed by nested functions // (-1 if neither this function nor any enclosing ones access variables from enclosing functions) int depth; + bool nestedContextCreated; // holds whether nested context is created llvm::Value* _arguments; llvm::Value* _argptr;