mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 20:37:25 +03:00
Implement -nested-ctx=hybrid
This commit is contained in:
parent
8820024070
commit
751f528969
5 changed files with 194 additions and 25 deletions
|
@ -673,13 +673,6 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
// debug info - after all allocas, but before any llvm.dbg.declare etc
|
// debug info - after all allocas, but before any llvm.dbg.declare etc
|
||||||
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
||||||
|
|
||||||
// need result variable?
|
|
||||||
if (fd->vresult) {
|
|
||||||
Logger::println("vresult value");
|
|
||||||
fd->vresult->ir.irLocal = new IrLocal(fd->vresult);
|
|
||||||
fd->vresult->ir.irLocal->value = DtoAlloca(DtoType(fd->vresult->type), "function_vresult");
|
|
||||||
}
|
|
||||||
|
|
||||||
// this hack makes sure the frame pointer elimination optimization is disabled.
|
// this hack makes sure the frame pointer elimination optimization is disabled.
|
||||||
// this this eliminates a bunch of inline asm related issues.
|
// this this eliminates a bunch of inline asm related issues.
|
||||||
if (fd->inlineAsm)
|
if (fd->inlineAsm)
|
||||||
|
@ -778,6 +771,18 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
|
|
||||||
DtoCreateNestedContext(fd);
|
DtoCreateNestedContext(fd);
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
if (fd->vresult && fd->vresult->nestedrefs.dim)
|
||||||
|
#else
|
||||||
|
if (fd->vresult && fd->vresult->nestedref)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
DtoNestedInit(fd->vresult);
|
||||||
|
} else if (fd->vresult) {
|
||||||
|
fd->vresult->ir.irLocal = new IrLocal(fd->vresult);
|
||||||
|
fd->vresult->ir.irLocal->value = DtoAlloca(DtoType(fd->vresult->type), fd->vresult->toChars());
|
||||||
|
}
|
||||||
|
|
||||||
// copy _argptr and _arguments to a memory location
|
// copy _argptr and _arguments to a memory location
|
||||||
if (f->linkage == LINKd && f->varargs == 1)
|
if (f->linkage == LINKd && f->varargs == 1)
|
||||||
{
|
{
|
||||||
|
|
196
gen/nested.cpp
196
gen/nested.cpp
|
@ -22,12 +22,12 @@ enum NestedCtxType {
|
||||||
// TODO: Functions without any variables accessed by nested functions, but
|
// TODO: Functions without any variables accessed by nested functions, but
|
||||||
// with a parent whose variables are accessed, can use the parent's
|
// with a parent whose variables are accessed, can use the parent's
|
||||||
// context.
|
// context.
|
||||||
|
// NOTE: This is what DMD seems to do.
|
||||||
NCStruct,
|
NCStruct,
|
||||||
|
|
||||||
/// Context is an array of pointers to nested contexts. Each function with variables
|
/// Context is a list of pointers to structs. Each function with variables
|
||||||
/// accessed by nested functions puts them in a struct, and appends a pointer to that
|
/// accessed by nested functions puts them in a struct, and appends a
|
||||||
/// struct to the array.
|
/// pointer to that struct to it's local copy of the list.
|
||||||
// FIXME: implement
|
|
||||||
NCHybrid
|
NCHybrid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,9 +37,9 @@ static cl::opt<NestedCtxType> nestedCtx("nested-ctx",
|
||||||
cl::values(
|
cl::values(
|
||||||
clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"),
|
clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"),
|
||||||
//clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"),
|
//clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"),
|
||||||
//clEnumValN(NCHybrid, "hybrid", "Array of pointers to structs of variables"),
|
clEnumValN(NCHybrid, "hybrid", "List of pointers to structs of variables, one per level."),
|
||||||
clEnumValEnd),
|
clEnumValEnd),
|
||||||
cl::init(NCArray));
|
cl::init(NCHybrid));
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
@ -47,8 +47,20 @@ static cl::opt<NestedCtxType> nestedCtx("nested-ctx",
|
||||||
// NESTED VARIABLE HELPERS
|
// NESTED VARIABLE HELPERS
|
||||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
static FuncDeclaration* getParentFunc(Dsymbol* sym) {
|
||||||
|
Dsymbol* parent = sym->parent;
|
||||||
|
assert(parent);
|
||||||
|
while (parent && !parent->isFuncDeclaration())
|
||||||
|
parent = parent->parent;
|
||||||
|
|
||||||
|
return (parent ? parent->isFuncDeclaration() : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
|
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
|
||||||
{
|
{
|
||||||
|
Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars());
|
||||||
|
LOG_SCOPE;
|
||||||
|
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
// Locate context value
|
// Locate context value
|
||||||
|
|
||||||
|
@ -89,6 +101,18 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
|
||||||
val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
|
val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
|
||||||
return new DVarValue(astype, vd, val);
|
return new DVarValue(astype, vd, val);
|
||||||
}
|
}
|
||||||
|
else if (nestedCtx == NCHybrid) {
|
||||||
|
FuncDeclaration *parentfunc = getParentFunc(vd);
|
||||||
|
assert(parentfunc && "No parent function for nested variable?");
|
||||||
|
|
||||||
|
LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(parentfunc->ir.irFunc->framesType));
|
||||||
|
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
|
||||||
|
val = DtoLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str());
|
||||||
|
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
|
||||||
|
if (vd->ir.irLocal->byref)
|
||||||
|
val = DtoLoad(val);
|
||||||
|
return new DVarValue(astype, vd, val);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
assert(0 && "Not implemented yet");
|
assert(0 && "Not implemented yet");
|
||||||
}
|
}
|
||||||
|
@ -96,6 +120,11 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
|
||||||
|
|
||||||
void DtoNestedInit(VarDeclaration* vd)
|
void DtoNestedInit(VarDeclaration* vd)
|
||||||
{
|
{
|
||||||
|
Logger::println("DtoNestedInit for %s", vd->toChars());
|
||||||
|
LOG_SCOPE
|
||||||
|
|
||||||
|
LLValue* nestedVar = gIR->func()->decl->ir.irFunc->nestedVar;
|
||||||
|
|
||||||
if (nestedCtx == NCArray) {
|
if (nestedCtx == NCArray) {
|
||||||
// alloca as usual if no value already
|
// alloca as usual if no value already
|
||||||
if (!vd->ir.irLocal->value)
|
if (!vd->ir.irLocal->value)
|
||||||
|
@ -103,13 +132,29 @@ void DtoNestedInit(VarDeclaration* vd)
|
||||||
|
|
||||||
// store the address into the nested vars array
|
// store the address into the nested vars array
|
||||||
assert(vd->ir.irLocal->nestedIndex >= 0);
|
assert(vd->ir.irLocal->nestedIndex >= 0);
|
||||||
LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex);
|
LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex);
|
||||||
|
|
||||||
assert(isaPointer(vd->ir.irLocal->value));
|
assert(isaPointer(vd->ir.irLocal->value));
|
||||||
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
||||||
|
|
||||||
DtoStore(val, gep);
|
DtoStore(val, gep);
|
||||||
}
|
}
|
||||||
|
else if (nestedCtx == NCHybrid) {
|
||||||
|
assert(vd->ir.irLocal->value && "Nested variable without storage?");
|
||||||
|
if (!vd->isParameter() && (vd->isRef() || vd->isOut())) {
|
||||||
|
Logger::println("Initializing non-parameter byref value");
|
||||||
|
LLValue* framep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedDepth);
|
||||||
|
|
||||||
|
FuncDeclaration *parentfunc = getParentFunc(vd);
|
||||||
|
assert(parentfunc && "No parent function for nested variable?");
|
||||||
|
LLValue* frame = DtoLoad(framep, (std::string(".frame.") + parentfunc->toChars()).c_str());
|
||||||
|
|
||||||
|
LLValue* slot = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex);
|
||||||
|
DtoStore(vd->ir.irLocal->value, slot);
|
||||||
|
} else {
|
||||||
|
// Already initialized in DtoCreateNestedContext
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
assert(0 && "Not implemented yet");
|
assert(0 && "Not implemented yet");
|
||||||
}
|
}
|
||||||
|
@ -145,6 +190,9 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoCreateNestedContext(FuncDeclaration* fd) {
|
void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||||
|
Logger::println("DtoCreateNestedContext for %s", fd->toChars());
|
||||||
|
LOG_SCOPE
|
||||||
|
|
||||||
if (nestedCtx == NCArray) {
|
if (nestedCtx == NCArray) {
|
||||||
// construct nested variables array
|
// construct nested variables array
|
||||||
if (!fd->nestedVars.empty())
|
if (!fd->nestedVars.empty())
|
||||||
|
@ -228,18 +276,130 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||||
|
|
||||||
vd->ir.irLocal->nestedIndex = idx++;
|
vd->ir.irLocal->nestedIndex = idx++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// fixup nested result variable
|
}
|
||||||
#if DMDV2
|
else if (nestedCtx == NCHybrid) {
|
||||||
if (fd->vresult && fd->vresult->nestedrefs.dim)
|
// construct nested variables array
|
||||||
#else
|
if (!fd->nestedVars.empty())
|
||||||
if (fd->vresult && fd->vresult->nestedref)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
Logger::println("nested vresult value: %s", fd->vresult->toChars());
|
Logger::println("has nested frame");
|
||||||
LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex);
|
// start with adding all enclosing parent frames until a static parent is reached
|
||||||
LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType());
|
typedef std::vector<const LLType*> TypeVec;
|
||||||
DtoStore(val, gep);
|
TypeVec frametypes;
|
||||||
|
if (!fd->isStatic()) {
|
||||||
|
Dsymbol* par = fd->toParent2();
|
||||||
|
while (par) {
|
||||||
|
if (FuncDeclaration* parfd = par->isFuncDeclaration()) {
|
||||||
|
// skip functions without nested parameters
|
||||||
|
if (!parfd->nestedVars.empty()) {
|
||||||
|
// Copy the types of parent function frames.
|
||||||
|
const LLStructType* parft = parfd->ir.irFunc->framesType;
|
||||||
|
frametypes.insert(frametypes.begin(), parft->element_begin(), parft->element_end());
|
||||||
|
break; // That's all the info needed.
|
||||||
|
}
|
||||||
|
} else if (ClassDeclaration* parcd = par->isClassDeclaration()) {
|
||||||
|
// skip
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
par = par->toParent2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned depth = frametypes.size();
|
||||||
|
|
||||||
|
// Construct a struct for the direct nested variables of this function, and update their indices to match.
|
||||||
|
// TODO: optimize ordering for minimal space usage?
|
||||||
|
TypeVec types;
|
||||||
|
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->nestedDepth = depth;
|
||||||
|
vd->ir.irLocal->nestedIndex = types.size();
|
||||||
|
if (vd->isParameter()) {
|
||||||
|
// Parameters already have storage associated with them (to handle byref etc.),
|
||||||
|
// so handle specially for now by storing a pointer instead of a value.
|
||||||
|
assert(vd->ir.irLocal->value);
|
||||||
|
// FIXME: don't do this for normal parameters?
|
||||||
|
types.push_back(vd->ir.irLocal->value->getType());
|
||||||
|
} 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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Append current frame type to frame type list
|
||||||
|
const LLType* frameType = LLStructType::get(types);
|
||||||
|
frametypes.push_back(LLPointerType::getUnqual(frameType));
|
||||||
|
|
||||||
|
// make struct type for nested frame list
|
||||||
|
const LLStructType* nestedVarsTy = LLStructType::get(frametypes);
|
||||||
|
|
||||||
|
// Store type in IrFunction
|
||||||
|
IrFunction* irfunction = fd->ir.irFunc;
|
||||||
|
irfunction->framesType = nestedVarsTy;
|
||||||
|
|
||||||
|
// alloca it
|
||||||
|
// FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca
|
||||||
|
LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".frame_list");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
ClassDeclaration* cd = fd->isMember2()->isClassDeclaration();
|
||||||
|
assert(cd);
|
||||||
|
assert(cd->vthis);
|
||||||
|
Logger::println("Indexing to 'this'");
|
||||||
|
src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis"));
|
||||||
|
}
|
||||||
|
src = DtoBitCast(src, getVoidPtrType());
|
||||||
|
LLValue* dst = DtoBitCast(nestedVars, getVoidPtrType());
|
||||||
|
DtoMemCpy(dst, src, DtoConstSize_t(depth * PTRSIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create frame for current function and append to frames list
|
||||||
|
LLValue* frame = DtoAlloca(frameType, ".frame");
|
||||||
|
// store current frame in list
|
||||||
|
DtoStore(frame, DtoGEPi(nestedVars, 0, depth));
|
||||||
|
|
||||||
|
// store context in IrFunction
|
||||||
|
irfunction->nestedVar = nestedVars;
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
DtoStore(vd->ir.irLocal->value, gep);
|
||||||
|
vd->ir.irLocal->byref = true;
|
||||||
|
} else if (vd->isRef() || vd->isOut()) {
|
||||||
|
// This slot is initialized in DtoNestedInit, to handle things like byref foreach variables
|
||||||
|
// which move around in memory.
|
||||||
|
vd->ir.irLocal->byref = true;
|
||||||
|
} else {
|
||||||
|
Logger::println("nested var: %s", vd->toChars());
|
||||||
|
if (vd->ir.irLocal->value)
|
||||||
|
Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n';
|
||||||
|
assert(!vd->ir.irLocal->value);
|
||||||
|
vd->ir.irLocal->value = gep;
|
||||||
|
vd->ir.irLocal->byref = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ IrFunction::IrFunction(FuncDeclaration* fd)
|
||||||
nestArg = NULL;
|
nestArg = NULL;
|
||||||
|
|
||||||
nestedVar = NULL;
|
nestedVar = NULL;
|
||||||
|
framesType = NULL;
|
||||||
|
|
||||||
_arguments = NULL;
|
_arguments = NULL;
|
||||||
_argptr = NULL;
|
_argptr = NULL;
|
||||||
|
|
|
@ -45,6 +45,7 @@ struct IrFunction : IrBase
|
||||||
llvm::Value* nestArg; // nested function 'this' arg
|
llvm::Value* nestArg; // nested function 'this' arg
|
||||||
|
|
||||||
llvm::Value* nestedVar; // nested var alloca
|
llvm::Value* nestedVar; // nested var alloca
|
||||||
|
const llvm::StructType* framesType; // type of nested context (not for -nested-ctx=array)
|
||||||
|
|
||||||
llvm::Value* _arguments;
|
llvm::Value* _arguments;
|
||||||
llvm::Value* _argptr;
|
llvm::Value* _argptr;
|
||||||
|
|
|
@ -26,6 +26,8 @@ struct IrLocal : IrVar
|
||||||
{
|
{
|
||||||
IrLocal(VarDeclaration* v);
|
IrLocal(VarDeclaration* v);
|
||||||
|
|
||||||
|
bool byref; // Not used for -nested-ctx=array
|
||||||
|
int nestedDepth; // ditto
|
||||||
int nestedIndex;
|
int nestedIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue