mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 22:50:53 +03:00
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:
parent
ee4285f934
commit
d4eafe53e0
4 changed files with 272 additions and 455 deletions
708
gen/nested.cpp
708
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<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
|
||||
|
@ -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<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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(0 && "Not implemented yet");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<VarDeclaration*>::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<VarDeclaration*>::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<LLValue*, 2> 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<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");
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue