Removed obsolete nested context styles.

NChybrid was the only one that didn't instantly trigger a "not
implemented" assertion on any code using nested function for a long
time, and removing the cruft greatly improves code readability
(maintainability is a moot point anyway given its current state).
This commit is contained in:
David Nadlinger 2012-09-04 01:58:19 +02:00
parent ee4285f934
commit d4eafe53e0
4 changed files with 272 additions and 455 deletions

View file

@ -807,14 +807,14 @@ void DtoDefineFunction(FuncDeclaration* fd)
DtoCreateNestedContext(fd); DtoCreateNestedContext(fd);
if (fd->vresult && !
#if DMDV2 #if DMDV2
if (fd->vresult && fd->vresult->nestedrefs.dim) // FIXME: not sure here :/ fd->vresult->nestedrefs.dim // FIXME: not sure here :/
#else #else
if (fd->vresult && fd->vresult->nestedref) fd->vresult->nestedref
#endif #endif
)
{ {
DtoNestedInit(fd->vresult);
} else if (fd->vresult) {
DtoVarDeclaration(fd->vresult); DtoVarDeclaration(fd->vresult);
} }

View file

@ -1029,10 +1029,10 @@ void DtoVarDeclaration(VarDeclaration* vd)
#endif #endif
{ {
Logger::println("has nestedref set (referenced by nested function/delegate)"); Logger::println("has nestedref set (referenced by nested function/delegate)");
assert(vd->ir.irLocal); assert(vd->ir.irLocal && "irLocal is expected to be already set by DtoCreateNestedContext");
DtoNestedInit(vd);
} }
else if(vd->ir.irLocal)
if(vd->ir.irLocal)
{ {
// Nothing to do if it has already been allocated. // Nothing to do if it has already been allocated.
} }
@ -1265,8 +1265,6 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr)
} }
else else
assert(!addr || addr == var->ir.irLocal->value); assert(!addr || addr == var->ir.irLocal->value);
DtoNestedInit(var);
} }
// normal local variable // normal local variable
else else

View file

@ -12,42 +12,6 @@
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
namespace cl = llvm::cl; 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<NestedCtxType> 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 // NESTED VARIABLE HELPERS
@ -168,94 +132,51 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
//////////////////////////////////// ////////////////////////////////////
// Extract variable from nested context // Extract variable from nested context
if (nestedCtx == NCArray) { LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType));
LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); Logger::cout() << "Context: " << *val << '\n';
val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); 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); val = DtoAlignedLoad(val);
assert(vd->ir.irLocal->value); //dwarfOpDeref(dwarfAddr);
val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); Logger::cout() << "Was byref, now: " << *val << '\n';
return new DVarValue(astype, vd, val);
}
else if (nestedCtx == NCHybrid) {
LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType));
Logger::cout() << "Context: " << *val << '\n';
Logger::cout() << "of type: " << *val->getType() << '\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) if (dwarfValue && global.params.symdebug)
{ DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr);
Logger::println("DtoNestedInit for %s", vd->toChars());
LOG_SCOPE
IrFunction* irfunc = gIR->func()->decl->ir.irFunc; return new DVarValue(astype, vd, val);
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");
}
} }
#if DMDV2 #if DMDV2
@ -316,60 +237,60 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
{ {
return llvm::UndefValue::get(getVoidPtrType()); 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 struct FuncDeclaration* fd = 0;
// enclosing scopes, it doesn't matter what we pass. #if DMDV2
// Tell LLVM about it by passing an 'undef'. if (AggregateDeclaration *ad = sym->isAggregateDeclaration())
if (symfd && symfd->ir.irFunc->depth == -1) // If sym is a nested struct or a nested class, pass the frame
return llvm::UndefValue::get(getVoidPtrType()); // 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 // if this is for a function that doesn't access variables from
// one we got, adjust it. // enclosing scopes, it doesn't matter what we pass.
fd = getParentFunc(symfd, true); // 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("Context is from %s", ctxfd->toChars());
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());
unsigned neededDepth = fd->ir.irFunc->depth; unsigned neededDepth = fd->ir.irFunc->depth;
unsigned ctxDepth = ctxfd->ir.irFunc->depth; unsigned ctxDepth = ctxfd->ir.irFunc->depth;
Logger::cout() << "Needed depth: " << neededDepth << '\n'; Logger::cout() << "Needed depth: " << neededDepth << '\n';
Logger::cout() << "Context depth: " << ctxDepth << '\n'; Logger::cout() << "Context depth: " << ctxDepth << '\n';
if (neededDepth >= ctxDepth) { if (neededDepth >= ctxDepth) {
// assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); // 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 // fd needs the same context as we do, so all is well
Logger::println("Calling sibling function or directly nested function"); Logger::println("Calling sibling function or directly nested function");
} else { } else {
val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType));
val = DtoGEPi(val, 0, neededDepth); val = DtoGEPi(val, 0, neededDepth);
val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str());
}
} }
} }
Logger::cout() << "result = " << *val << '\n'; Logger::cout() << "result = " << *val << '\n';
Logger::cout() << "of type " << *val->getType() << '\n'; Logger::cout() << "of type " << *val->getType() << '\n';
return val; return val;
@ -397,111 +318,106 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) {
} }
#endif #endif
if (nestedCtx == NCHybrid) { // construct nested variables array
// construct nested variables array if (!fd->nestedVars.empty())
if (!fd->nestedVars.empty()) {
{ Logger::println("has nested frame");
Logger::println("has nested frame"); // start with adding all enclosing parent frames until a static parent is reached
// start with adding all enclosing parent frames until a static parent is reached
LLStructType* innerFrameType = NULL; LLStructType* innerFrameType = NULL;
unsigned depth = -1; unsigned depth = -1;
if (!fd->isStatic()) { if (!fd->isStatic()) {
if (FuncDeclaration* parfd = getParentFunc(fd, true)) { if (FuncDeclaration* parfd = getParentFunc(fd, true)) {
// Make sure the parent has already been analyzed. // Make sure the parent has already been analyzed.
DtoCreateNestedContextType(parfd); DtoCreateNestedContextType(parfd);
innerFrameType = parfd->ir.irFunc->frameType; innerFrameType = parfd->ir.irFunc->frameType;
if (innerFrameType) if (innerFrameType)
depth = parfd->ir.irFunc->depth; depth = parfd->ir.irFunc->depth;
}
} }
fd->ir.irFunc->depth = ++depth;
Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';
typedef std::vector<LLType*> 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<VarDeclaration*>::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;
} }
} fd->ir.irFunc->depth = ++depth;
else {
assert(0 && "Not implemented yet"); Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';
typedef std::vector<LLType*> 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<VarDeclaration*>::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); DtoCreateNestedContextType(fd);
if (nestedCtx == NCArray) { // construct nested variables array
// construct nested variables array if (!fd->nestedVars.empty())
if (!fd->nestedVars.empty()) {
{ IrFunction* irfunction = fd->ir.irFunc;
Logger::println("has nested frame"); unsigned depth = irfunction->depth;
// start with adding all enclosing parent frames until a static parent is reached LLStructType *frameType = irfunction->frameType;
int nparelems = 0; // Create frame for current function and append to frames list
if (!fd->isStatic()) // FIXME: alignment ?
{ LLValue* frame = 0;
Dsymbol* par = fd->toParent2(); #if DMDV2
while (par) if (fd->needsClosure())
{ frame = DtoGcMalloc(frameType, ".frame");
if (FuncDeclaration* parfd = par->isFuncDeclaration()) else
{ #endif
nparelems += parfd->nestedVars.size(); frame = DtoRawAlloca(frameType, 0, ".frame");
// stop at first static
if (parfd->isStatic())
break;
}
else if (par->isClassDeclaration())
{
// nothing needed
}
else
{
break;
}
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; if (depth > 1) {
src = DtoBitCast(src, getVoidPtrType());
// make array type for nested vars LLValue* dst = DtoBitCast(frame, getVoidPtrType());
LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE),
// 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),
getABITypeAlign(getVoidPtrType())); 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 // store context in IrFunction
irfunction->nestedVar = nestedVars; irfunction->nestedVar = frame;
// go through all nested vars and assign indices // go through all nested vars and assign addresses where possible.
int idx = nparelems; for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) {
{ VarDeclaration* vd = *i;
VarDeclaration* vd = *i;
if (!vd->ir.irLocal)
vd->ir.irLocal = new IrLocal(vd);
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()); storeVariable(vd, gep);
LLValue* gep = DtoGEPi(nestedVars, 0, idx);
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
DtoAlignedStore(val, gep);
} }
else 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<LLValue*, 2> addr;
dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex);
DtoDwarfLocalVariable(frame, vd, addr);
} }
} }
} } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) {
else if (nestedCtx == NCHybrid) { // Propagate context arg properties if the context arg is passed on unmodified.
// construct nested variables array DtoDeclareFunction(parFunc);
if (!fd->nestedVars.empty()) fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType;
{ fd->ir.irFunc->depth = parFunc->ir.irFunc->depth;
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<VarDeclaration*>::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<LLValue*, 2> 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");
} }
} }

View file

@ -13,9 +13,6 @@
/// Creates the context value for a nested function. /// Creates the context value for a nested function.
void DtoCreateNestedContext(FuncDeclaration* fd); 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. /// Resolves the nested context for classes and structs with arbitrary nesting.
#if DMDV2 #if DMDV2
void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value); void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value);