diff --git a/gen/functions.cpp b/gen/functions.cpp index 5e540c21..73eb433e 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -807,14 +807,14 @@ void DtoDefineFunction(FuncDeclaration* fd) DtoCreateNestedContext(fd); + if (fd->vresult && ! #if DMDV2 - if (fd->vresult && fd->vresult->nestedrefs.dim) // FIXME: not sure here :/ + fd->vresult->nestedrefs.dim // FIXME: not sure here :/ #else - if (fd->vresult && fd->vresult->nestedref) + fd->vresult->nestedref #endif + ) { - DtoNestedInit(fd->vresult); - } else if (fd->vresult) { DtoVarDeclaration(fd->vresult); } diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index de90a17f..8db92d06 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1029,10 +1029,10 @@ void DtoVarDeclaration(VarDeclaration* vd) #endif { Logger::println("has nestedref set (referenced by nested function/delegate)"); - assert(vd->ir.irLocal); - DtoNestedInit(vd); + assert(vd->ir.irLocal && "irLocal is expected to be already set by DtoCreateNestedContext"); } - else if(vd->ir.irLocal) + + if(vd->ir.irLocal) { // Nothing to do if it has already been allocated. } @@ -1265,8 +1265,6 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr) } else assert(!addr || addr == var->ir.irLocal->value); - - DtoNestedInit(var); } // normal local variable else diff --git a/gen/nested.cpp b/gen/nested.cpp index 7688d6da..e84f7446 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -12,42 +12,6 @@ #include "llvm/Support/CommandLine.h" namespace cl = llvm::cl; -/// What the context pointer for a nested function looks like -enum NestedCtxType { - /// Context is void*[] of pointers to variables. - /// Variables from higher levels are at the front. - NCArray, - - /// Context is a struct containing variables belonging to the parent function. - /// If the parent function itself has a parent function, one of the members is - /// a pointer to its context. (linked-list style) - // FIXME: implement - // TODO: Functions without any variables accessed by nested functions, but - // with a parent whose variables are accessed, can use the parent's - // context. - // NOTE: This is what DMD seems to do. - NCStruct, - - /// Context is a list of pointers to structs of variables, followed by the - /// variables of the inner-most function with variables accessed by nested - /// functions. The initial pointers point to similar structs for enclosing - /// functions. - /// Only functions whose variables are accessed by nested functions create - /// new frames, others just pass on what got passed in. - NCHybrid -}; - -static cl::opt nestedCtx("nested-ctx", - cl::desc("How to construct a nested function's context:"), - cl::ZeroOrMore, - cl::values( - clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"), - //clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"), - clEnumValN(NCHybrid, "hybrid", "List of pointers to structs of variables, one per level."), - clEnumValEnd), - cl::init(NCHybrid)); - - /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// // NESTED VARIABLE HELPERS @@ -168,94 +132,51 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) //////////////////////////////////// // Extract variable from nested context - if (nestedCtx == NCArray) { - LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); - val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); + LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); + Logger::cout() << "Context: " << *val << '\n'; + Logger::cout() << "of type: " << *val->getType() << '\n'; + + unsigned vardepth = vd->ir.irLocal->nestedDepth; + unsigned funcdepth = irfunc->depth; + + Logger::cout() << "Variable: " << vd->toChars() << '\n'; + Logger::cout() << "Variable depth: " << vardepth << '\n'; + Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; + Logger::cout() << "Function depth: " << funcdepth << '\n'; + + if (vardepth == funcdepth) { + // This is not always handled above because functions without + // variables accessed by nested functions don't create new frames. + Logger::println("Same depth"); + } else { + // Load frame pointer and index that... + if (dwarfValue && global.params.symdebug) { + dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); + dwarfOpDeref(dwarfAddr); + } + Logger::println("Lower depth"); + val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); + Logger::cout() << "Frame index: " << *val << '\n'; + val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); + Logger::cout() << "Frame: " << *val << '\n'; + } + + if (dwarfValue && global.params.symdebug) + dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); + val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); + Logger::cout() << "Addr: " << *val << '\n'; + Logger::cout() << "of type: " << *val->getType() << '\n'; + if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { val = DtoAlignedLoad(val); - assert(vd->ir.irLocal->value); - val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); - return new DVarValue(astype, vd, val); - } - else if (nestedCtx == NCHybrid) { - LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); - Logger::cout() << "Context: " << *val << '\n'; + //dwarfOpDeref(dwarfAddr); + Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; - - unsigned vardepth = vd->ir.irLocal->nestedDepth; - unsigned funcdepth = irfunc->depth; - - Logger::cout() << "Variable: " << vd->toChars() << '\n'; - Logger::cout() << "Variable depth: " << vardepth << '\n'; - Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; - Logger::cout() << "Function depth: " << funcdepth << '\n'; - - if (vardepth == funcdepth) { - // This is not always handled above because functions without - // variables accessed by nested functions don't create new frames. - Logger::println("Same depth"); - } else { - // Load frame pointer and index that... - if (dwarfValue && global.params.symdebug) { - dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); - dwarfOpDeref(dwarfAddr); - } - Logger::println("Lower depth"); - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); - Logger::cout() << "Frame index: " << *val << '\n'; - val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); - Logger::cout() << "Frame: " << *val << '\n'; - } - - if (dwarfValue && global.params.symdebug) - dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - Logger::cout() << "Addr: " << *val << '\n'; - Logger::cout() << "of type: " << *val->getType() << '\n'; - if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { - val = DtoAlignedLoad(val); - //dwarfOpDeref(dwarfAddr); - Logger::cout() << "Was byref, now: " << *val << '\n'; - Logger::cout() << "of type: " << *val->getType() << '\n'; - } - - if (dwarfValue && global.params.symdebug) - DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); - - return new DVarValue(astype, vd, val); } - else { - assert(0 && "Not implemented yet"); - } -} -void DtoNestedInit(VarDeclaration* vd) -{ - Logger::println("DtoNestedInit for %s", vd->toChars()); - LOG_SCOPE + if (dwarfValue && global.params.symdebug) + DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); - IrFunction* irfunc = gIR->func()->decl->ir.irFunc; - LLValue* nestedVar = irfunc->nestedVar; - - if (nestedCtx == NCArray) { - // alloca as usual if no value already - if (!vd->ir.irLocal->value) - vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars()); - - // store the address into the nested vars array - assert(vd->ir.irLocal->nestedIndex >= 0); - LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); - - assert(isaPointer(vd->ir.irLocal->value)); - LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); - - DtoAlignedStore(val, gep); - } - else if (nestedCtx == NCHybrid) { - // Already initialized in DtoCreateNestedContext. - } - else { - assert(0 && "Not implemented yet"); - } + return new DVarValue(astype, vd, val); } #if DMDV2 @@ -316,60 +237,60 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) { return llvm::UndefValue::get(getVoidPtrType()); } - if (nestedCtx == NCHybrid) { - struct FuncDeclaration* fd = 0; - #if DMDV2 - if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) - // If sym is a nested struct or a nested class, pass the frame - // of the function where sym is declared. - fd = ad->toParent()->isFuncDeclaration(); - else - #endif - 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()); + struct FuncDeclaration* fd = 0; +#if DMDV2 + if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) + // If sym is a nested struct or a nested class, pass the frame + // of the function where sym is declared. + fd = ad->toParent()->isFuncDeclaration(); + else +#endif + 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 sym is a nested function, and it's parent context is different than the - // one we got, adjust it. - fd = getParentFunc(symfd, true); + // 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. + fd = getParentFunc(symfd, true); + } + if (fd) { + Logger::println("For nested function, parent is %s", fd->toChars()); + FuncDeclaration* ctxfd = irfunc->decl; + Logger::println("Current function is %s", ctxfd->toChars()); + if (fromParent) { + ctxfd = getParentFunc(ctxfd, true); + assert(ctxfd && "Context from outer function, but no outer function?"); } - if (fd) { - Logger::println("For nested function, parent is %s", fd->toChars()); - FuncDeclaration* ctxfd = irfunc->decl; - Logger::println("Current function is %s", ctxfd->toChars()); - if (fromParent) { - ctxfd = getParentFunc(ctxfd, true); - assert(ctxfd && "Context from outer function, but no outer function?"); - } - Logger::println("Context is from %s", ctxfd->toChars()); + Logger::println("Context is from %s", ctxfd->toChars()); - unsigned neededDepth = fd->ir.irFunc->depth; - unsigned ctxDepth = ctxfd->ir.irFunc->depth; + unsigned neededDepth = fd->ir.irFunc->depth; + unsigned ctxDepth = ctxfd->ir.irFunc->depth; - Logger::cout() << "Needed depth: " << neededDepth << '\n'; - Logger::cout() << "Context depth: " << ctxDepth << '\n'; + 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 - Logger::println("Calling sibling function or directly nested function"); - } else { - val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); - val = DtoGEPi(val, 0, neededDepth); - val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); - } + 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 + Logger::println("Calling sibling function or directly nested function"); + } else { + val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); + val = DtoGEPi(val, 0, neededDepth); + val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); } } + Logger::cout() << "result = " << *val << '\n'; Logger::cout() << "of type " << *val->getType() << '\n'; return val; @@ -397,111 +318,106 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { } #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 + // 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 - LLStructType* innerFrameType = NULL; - unsigned depth = -1; - if (!fd->isStatic()) { - if (FuncDeclaration* parfd = getParentFunc(fd, true)) { - // Make sure the parent has already been analyzed. - DtoCreateNestedContextType(parfd); + LLStructType* innerFrameType = NULL; + unsigned depth = -1; + if (!fd->isStatic()) { + if (FuncDeclaration* parfd = getParentFunc(fd, true)) { + // Make sure the parent has already been analyzed. + DtoCreateNestedContextType(parfd); - innerFrameType = parfd->ir.irFunc->frameType; - if (innerFrameType) - depth = parfd->ir.irFunc->depth; - } + 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 will have storage associated with them (to handle byref etc.), - // so handle those cases specially by storing a pointer instead of a value. - IrParameter * irparam = vd->ir.irParam; - LLValue* value = irparam->value; - assert(value); - LLType* type = value->getType(); - bool refout = vd->storage_class & (STCref | STCout); - bool lazy = vd->storage_class & STClazy; - bool byref = irparam->arg->byref; - #if STRUCTTHISREF - bool isVthisPtr = irparam->isVthis && !byref; - #else - bool isVthisPtr = irparam->isVthis; - #endif - if ((!refout && (!byref || lazy)) || isVthisPtr) { - // This will be copied to the nesting frame. - if (lazy) - type = type->getContainedType(0); - else - type = DtoType(vd->type); - } else { - } - types.push_back(type); - } else if (isSpecialRefVar(vd)) { - 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'; - } - } - - LLStructType* frameType = LLStructType::create(gIR->context(), types, - std::string("nest.") + fd->toChars()); - - 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"); + 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 will have storage associated with them (to handle byref etc.), + // so handle those cases specially by storing a pointer instead of a value. + IrParameter * irparam = vd->ir.irParam; + LLValue* value = irparam->value; + assert(value); + LLType* type = value->getType(); + bool refout = vd->storage_class & (STCref | STCout); + bool lazy = vd->storage_class & STClazy; + bool byref = irparam->arg->byref; +#if STRUCTTHISREF + bool isVthisPtr = irparam->isVthis && !byref; +#else + bool isVthisPtr = irparam->isVthis; +#endif + if ((!refout && (!byref || lazy)) || isVthisPtr) { + // This will be copied to the nesting frame. + if (lazy) + type = type->getContainedType(0); + else + type = DtoType(vd->type); + } else { + } + types.push_back(type); + } else if (isSpecialRefVar(vd)) { + 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'; + } + } + + LLStructType* frameType = LLStructType::create(gIR->context(), types, + std::string("nest.") + fd->toChars()); + + 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; } } @@ -512,197 +428,103 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { DtoCreateNestedContextType(fd); - if (nestedCtx == NCArray) { - // 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 - int nparelems = 0; - if (!fd->isStatic()) - { - Dsymbol* par = fd->toParent2(); - while (par) - { - if (FuncDeclaration* parfd = par->isFuncDeclaration()) - { - nparelems += parfd->nestedVars.size(); - // stop at first static - if (parfd->isStatic()) - break; - } - else if (par->isClassDeclaration()) - { - // nothing needed - } - else - { - break; - } + // construct nested variables array + if (!fd->nestedVars.empty()) + { + IrFunction* irfunction = fd->ir.irFunc; + unsigned depth = irfunction->depth; + LLStructType *frameType = irfunction->frameType; + // Create frame for current function and append to frames list + // FIXME: alignment ? + LLValue* frame = 0; +#if DMDV2 + if (fd->needsClosure()) + frame = DtoGcMalloc(frameType, ".frame"); + else +#endif + frame = DtoRawAlloca(frameType, 0, ".frame"); - par = par->toParent2(); - } + + // copy parent frames into beginning + if (depth != 0) { + LLValue* src = irfunction->nestArg; + if (!src) { + assert(irfunction->thisArg); + assert(fd->isMember2()); + LLValue* thisval = DtoLoad(irfunction->thisArg); +#if DMDV2 + AggregateDeclaration* cd = fd->isMember2(); +#else + ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); +#endif + assert(cd); + assert(cd->vthis); + Logger::println("Indexing to 'this'"); +#if DMDV2 + if (cd->isStructDeclaration()) + src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); + else +#endif + src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); + } else { + src = DtoLoad(src); } - int nelems = fd->nestedVars.size() + nparelems; - - // make array type for nested vars - LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); - - // alloca it - // FIXME align ? - LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars"); - - IrFunction* irfunction = fd->ir.irFunc; - - // copy parent frame into beginning - if (nparelems) - { - LLValue* src = irfunction->nestArg; - if (!src) - { - assert(irfunction->thisArg); - assert(fd->isMember2()); - LLValue* thisval = DtoLoad(irfunction->thisArg); - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); - assert(cd); - assert(cd->vthis); - src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); - } else { - src = DtoLoad(src); - } - DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE), + if (depth > 1) { + src = DtoBitCast(src, getVoidPtrType()); + LLValue* dst = DtoBitCast(frame, getVoidPtrType()); + DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), getABITypeAlign(getVoidPtrType())); } + // Copy nestArg into framelist; the outer frame is not in the list of pointers + src = DtoBitCast(src, frameType->getContainedType(depth-1)); + LLValue* gep = DtoGEPi(frame, 0, depth-1); + DtoAlignedStore(src, gep); + } - // store in IrFunction - irfunction->nestedVar = nestedVars; + // store context in IrFunction + irfunction->nestedVar = frame; - // go through all nested vars and assign indices - int idx = nparelems; - 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); + // go through all nested vars and assign addresses where possible. + for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) + { + VarDeclaration* vd = *i; - if (vd->isParameter()) + LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); + if (vd->isParameter()) { + Logger::println("nested param: %s", vd->toChars()); + LOG_SCOPE + IrParameter* parm = vd->ir.irParam; + + if (parm->arg->byref) { - Logger::println("nested param: %s", vd->toChars()); - LLValue* gep = DtoGEPi(nestedVars, 0, idx); - LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); - DtoAlignedStore(val, gep); + storeVariable(vd, gep); } else { - Logger::println("nested var: %s", vd->toChars()); + Logger::println("Copying to nested frame"); + // The parameter value is an alloca'd stack slot. + // Copy to the nesting frame and leave the alloca for + // the optimizers to clean up. + DtoStore(DtoLoad(parm->value), gep); + gep->takeName(parm->value); + parm->value = gep; } + } else { + Logger::println("nested var: %s", vd->toChars()); + assert(!vd->ir.irLocal->value); + vd->ir.irLocal->value = gep; + } - vd->ir.irLocal->nestedIndex = idx++; + if (global.params.symdebug) { + LLSmallVector addr; + dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); + DtoDwarfLocalVariable(frame, vd, addr); } } - } - else if (nestedCtx == NCHybrid) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - IrFunction* irfunction = fd->ir.irFunc; - unsigned depth = irfunction->depth; - LLStructType *frameType = irfunction->frameType; - // Create frame for current function and append to frames list - // FIXME: alignment ? - 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) { - LLValue* src = irfunction->nestArg; - if (!src) { - assert(irfunction->thisArg); - assert(fd->isMember2()); - LLValue* thisval = DtoLoad(irfunction->thisArg); -#if DMDV2 - AggregateDeclaration* cd = fd->isMember2(); -#else - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); -#endif - assert(cd); - assert(cd->vthis); - Logger::println("Indexing to 'this'"); -#if DMDV2 - if (cd->isStructDeclaration()) - src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); - else -#endif - src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); - } else { - src = DtoLoad(src); - } - if (depth > 1) { - src = DtoBitCast(src, getVoidPtrType()); - LLValue* dst = DtoBitCast(frame, getVoidPtrType()); - DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), - getABITypeAlign(getVoidPtrType())); - } - // Copy nestArg into framelist; the outer frame is not in the list of pointers - src = DtoBitCast(src, frameType->getContainedType(depth-1)); - LLValue* gep = DtoGEPi(frame, 0, depth-1); - DtoAlignedStore(src, gep); - } - - // store context in IrFunction - irfunction->nestedVar = frame; - - // go through all nested vars and assign addresses where possible. - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - - LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - if (vd->isParameter()) { - Logger::println("nested param: %s", vd->toChars()); - LOG_SCOPE - IrParameter* parm = vd->ir.irParam; - - if (parm->arg->byref) - { - storeVariable(vd, gep); - } - else - { - Logger::println("Copying to nested frame"); - // The parameter value is an alloca'd stack slot. - // Copy to the nesting frame and leave the alloca for - // the optimizers to clean up. - DtoStore(DtoLoad(parm->value), gep); - gep->takeName(parm->value); - parm->value = gep; - } - } else { - Logger::println("nested var: %s", vd->toChars()); - assert(!vd->ir.irLocal->value); - vd->ir.irLocal->value = gep; - } - - if (global.params.symdebug) { - LLSmallVector addr; - dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); - DtoDwarfLocalVariable(frame, vd, addr); - } - } - } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { - // Propagate context arg properties if the context arg is passed on unmodified. - DtoDeclareFunction(parFunc); - fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; - fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; - } - } - else { - assert(0 && "Not implemented yet"); + } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { + // Propagate context arg properties if the context arg is passed on unmodified. + DtoDeclareFunction(parFunc); + fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; + fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } } diff --git a/gen/nested.h b/gen/nested.h index 34fff976..91f0a002 100644 --- a/gen/nested.h +++ b/gen/nested.h @@ -13,9 +13,6 @@ /// Creates the context value for a nested function. void DtoCreateNestedContext(FuncDeclaration* fd); -/// Allocate space for variable accessed from nested function. -void DtoNestedInit(VarDeclaration* vd); - /// Resolves the nested context for classes and structs with arbitrary nesting. #if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value);