mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-05-14 22:11:29 +02:00
Isolate all knowledge of what a function's nested context looks like in a
single place. No functional change.
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "gen/functions.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/nested.h"
|
||||
|
||||
#include "ir/irstruct.h"
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "gen/classes.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/nested.h"
|
||||
|
||||
using namespace llvm::Attribute;
|
||||
|
||||
@@ -775,99 +776,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
fd->nestedVars.insert(fd->vresult);
|
||||
}
|
||||
|
||||
// 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 (ClassDeclaration* parcd = par->isClassDeclaration())
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
par = par->toParent2();
|
||||
}
|
||||
}
|
||||
int nelems = fd->nestedVars.size() + nparelems;
|
||||
|
||||
// make array type for nested vars
|
||||
const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);
|
||||
|
||||
// alloca it
|
||||
LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".nested_vars");
|
||||
|
||||
// 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"));
|
||||
}
|
||||
DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE));
|
||||
}
|
||||
|
||||
// store in IrFunction
|
||||
irfunction->nestedVar = nestedVars;
|
||||
|
||||
// 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);
|
||||
|
||||
if (vd->isParameter())
|
||||
{
|
||||
Logger::println("nested param: %s", vd->toChars());
|
||||
LLValue* gep = DtoGEPi(nestedVars, 0, idx);
|
||||
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
||||
DtoStore(val, gep);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::println("nested var: %s", vd->toChars());
|
||||
}
|
||||
|
||||
vd->ir.irLocal->nestedIndex = idx++;
|
||||
}
|
||||
|
||||
// fixup nested result variable
|
||||
#if DMDV2
|
||||
if (fd->vresult && fd->vresult->nestedrefs.dim) {
|
||||
#else
|
||||
if (fd->vresult && fd->vresult->nestedref) {
|
||||
#endif
|
||||
Logger::println("nested vresult value: %s", fd->vresult->toChars());
|
||||
LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex);
|
||||
LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType());
|
||||
DtoStore(val, gep);
|
||||
}
|
||||
}
|
||||
DtoCreateNestedContext(fd);
|
||||
|
||||
// copy _argptr and _arguments to a memory location
|
||||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "gen/typeinf.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/cl_options.h"
|
||||
#include "gen/nested.h"
|
||||
#include "ir/irmodule.h"
|
||||
|
||||
#include <stack>
|
||||
@@ -311,75 +312,6 @@ void DtoLeaveMonitor(LLValue* v)
|
||||
gIR->CreateCallOrInvoke(fn, v);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NESTED VARIABLE HELPERS
|
||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
|
||||
{
|
||||
Dsymbol* vdparent = vd->toParent2();
|
||||
assert(vdparent);
|
||||
|
||||
IrFunction* irfunc = gIR->func();
|
||||
|
||||
// is the nested variable in this scope?
|
||||
if (vdparent == irfunc->decl)
|
||||
{
|
||||
LLValue* val = vd->ir.getIrValue();
|
||||
return new DVarValue(astype, vd, val);
|
||||
}
|
||||
|
||||
// get it from the nested context
|
||||
LLValue* ctx = 0;
|
||||
if (irfunc->decl->isMember2())
|
||||
{
|
||||
ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
|
||||
LLValue* val = DtoLoad(irfunc->thisArg);
|
||||
ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
|
||||
}
|
||||
else
|
||||
ctx = irfunc->nestArg;
|
||||
assert(ctx);
|
||||
|
||||
assert(vd->ir.irLocal);
|
||||
LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
|
||||
val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex);
|
||||
val = DtoLoad(val);
|
||||
assert(vd->ir.irLocal->value);
|
||||
val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
|
||||
return new DVarValue(astype, vd, val);
|
||||
}
|
||||
|
||||
LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
|
||||
{
|
||||
Logger::println("DtoNestedContext for %s", sym->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
IrFunction* irfunc = gIR->func();
|
||||
|
||||
// if this func has its own vars that are accessed by nested funcs
|
||||
// use its own context
|
||||
if (irfunc->nestedVar)
|
||||
return irfunc->nestedVar;
|
||||
// otherwise, it may have gotten a context from the caller
|
||||
else if (irfunc->nestArg)
|
||||
return irfunc->nestArg;
|
||||
// or just have a this argument
|
||||
else if (irfunc->thisArg)
|
||||
{
|
||||
ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
|
||||
if (!cd || !cd->vthis)
|
||||
return getNullPtr(getVoidPtrType());
|
||||
LLValue* val = DtoLoad(irfunc->thisArg);
|
||||
return DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return getNullPtr(getVoidPtrType());
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ASSIGNMENT HELPER (store this in that)
|
||||
@@ -946,22 +878,7 @@ DValue* DtoDeclarationExp(Dsymbol* declaration)
|
||||
Logger::println("has nestedref set");
|
||||
assert(vd->ir.irLocal);
|
||||
|
||||
// alloca as usual if no value already
|
||||
if (!vd->ir.irLocal->value)
|
||||
{
|
||||
vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars());
|
||||
}
|
||||
|
||||
// store the address into the nested vars array
|
||||
|
||||
assert(vd->ir.irLocal->nestedIndex >= 0);
|
||||
LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex);
|
||||
|
||||
assert(isaPointer(vd->ir.irLocal->value));
|
||||
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
||||
|
||||
DtoStore(val, gep);
|
||||
|
||||
DtoNestedInit(vd);
|
||||
}
|
||||
// normal stack variable, allocate storage on the stack if it has not already been done
|
||||
else if(!vd->ir.irLocal) {
|
||||
@@ -1110,12 +1027,7 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr)
|
||||
else
|
||||
assert(!addr || addr == var->ir.irLocal->value);
|
||||
|
||||
// store the address into the nested vars array
|
||||
assert(var->ir.irLocal->nestedIndex >= 0);
|
||||
LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, var->ir.irLocal->nestedIndex);
|
||||
assert(isaPointer(var->ir.irLocal->value));
|
||||
LLValue* val = DtoBitCast(var->ir.irLocal->value, getVoidPtrType());
|
||||
DtoStore(val, gep);
|
||||
DtoNestedInit(var);
|
||||
}
|
||||
// normal local variable
|
||||
else
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
#define LDC_GEN_LLVMHELPERS_H
|
||||
|
||||
#include "gen/llvm.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
|
||||
// this is used for tracking try-finally, synchronized and volatile scopes
|
||||
struct EnclosingHandler
|
||||
@@ -64,15 +67,6 @@ void DtoEnterMonitor(LLValue* v);
|
||||
/// Leaves a monitor lock.
|
||||
void DtoLeaveMonitor(LLValue* v);
|
||||
|
||||
// nested variable and context helpers
|
||||
|
||||
/// Gets the context value for a call to a nested function or newing a nested
|
||||
/// class with arbitrary nesting.
|
||||
LLValue* DtoNestedContext(Loc loc, Dsymbol* sym);
|
||||
|
||||
/// Gets the DValue of a nested variable with arbitrary nesting.
|
||||
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd);
|
||||
|
||||
// basic operations
|
||||
void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs);
|
||||
|
||||
|
||||
190
gen/nested.cpp
Normal file
190
gen/nested.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "gen/nested.h"
|
||||
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/tollvm.h"
|
||||
|
||||
/****************************************************************************************/
|
||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NESTED VARIABLE HELPERS
|
||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
|
||||
{
|
||||
Dsymbol* vdparent = vd->toParent2();
|
||||
assert(vdparent);
|
||||
|
||||
IrFunction* irfunc = gIR->func();
|
||||
|
||||
// is the nested variable in this scope?
|
||||
if (vdparent == irfunc->decl)
|
||||
{
|
||||
LLValue* val = vd->ir.getIrValue();
|
||||
return new DVarValue(astype, vd, val);
|
||||
}
|
||||
|
||||
// get it from the nested context
|
||||
LLValue* ctx = 0;
|
||||
if (irfunc->decl->isMember2())
|
||||
{
|
||||
ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
|
||||
LLValue* val = DtoLoad(irfunc->thisArg);
|
||||
ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
|
||||
}
|
||||
else
|
||||
ctx = irfunc->nestArg;
|
||||
assert(ctx);
|
||||
|
||||
assert(vd->ir.irLocal);
|
||||
LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
|
||||
val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex);
|
||||
val = DtoLoad(val);
|
||||
assert(vd->ir.irLocal->value);
|
||||
val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
|
||||
return new DVarValue(astype, vd, val);
|
||||
}
|
||||
|
||||
void DtoNestedInit(VarDeclaration* vd)
|
||||
{
|
||||
// alloca as usual if no value already
|
||||
if (!vd->ir.irLocal->value)
|
||||
vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars());
|
||||
|
||||
// store the address into the nested vars array
|
||||
assert(vd->ir.irLocal->nestedIndex >= 0);
|
||||
LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex);
|
||||
|
||||
assert(isaPointer(vd->ir.irLocal->value));
|
||||
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
||||
|
||||
DtoStore(val, gep);
|
||||
}
|
||||
|
||||
LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
|
||||
{
|
||||
Logger::println("DtoNestedContext for %s", sym->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
IrFunction* irfunc = gIR->func();
|
||||
|
||||
// if this func has its own vars that are accessed by nested funcs
|
||||
// use its own context
|
||||
if (irfunc->nestedVar)
|
||||
return irfunc->nestedVar;
|
||||
// otherwise, it may have gotten a context from the caller
|
||||
else if (irfunc->nestArg)
|
||||
return irfunc->nestArg;
|
||||
// or just have a this argument
|
||||
else if (irfunc->thisArg)
|
||||
{
|
||||
ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
|
||||
if (!cd || !cd->vthis)
|
||||
return getNullPtr(getVoidPtrType());
|
||||
LLValue* val = DtoLoad(irfunc->thisArg);
|
||||
return DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return getNullPtr(getVoidPtrType());
|
||||
}
|
||||
}
|
||||
|
||||
void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||
// construct nested variables array
|
||||
if (!fd->nestedVars.empty())
|
||||
{
|
||||
Logger::println("has nested frame");
|
||||
// start with adding all enclosing parent frames until a static parent is reached
|
||||
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 (ClassDeclaration* parcd = par->isClassDeclaration())
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
par = par->toParent2();
|
||||
}
|
||||
}
|
||||
int nelems = fd->nestedVars.size() + nparelems;
|
||||
|
||||
// make array type for nested vars
|
||||
const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);
|
||||
|
||||
// alloca it
|
||||
LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".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"));
|
||||
}
|
||||
DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE));
|
||||
}
|
||||
|
||||
// store in IrFunction
|
||||
irfunction->nestedVar = nestedVars;
|
||||
|
||||
// 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);
|
||||
|
||||
if (vd->isParameter())
|
||||
{
|
||||
Logger::println("nested param: %s", vd->toChars());
|
||||
LLValue* gep = DtoGEPi(nestedVars, 0, idx);
|
||||
LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
|
||||
DtoStore(val, gep);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::println("nested var: %s", vd->toChars());
|
||||
}
|
||||
|
||||
vd->ir.irLocal->nestedIndex = idx++;
|
||||
}
|
||||
|
||||
// fixup nested result variable
|
||||
#if DMDV2
|
||||
if (fd->vresult && fd->vresult->nestedrefs.dim) {
|
||||
#else
|
||||
if (fd->vresult && fd->vresult->nestedref) {
|
||||
#endif
|
||||
Logger::println("nested vresult value: %s", fd->vresult->toChars());
|
||||
LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex);
|
||||
LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType());
|
||||
DtoStore(val, gep);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
gen/nested.h
Normal file
25
gen/nested.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef LDC_GEN_NESTED_H
|
||||
#define LDC_GEN_NESTED_H
|
||||
|
||||
#include "declaration.h"
|
||||
#include "mtype.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Nested variable and context helpers
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
/// Creates the context value for a nested function.
|
||||
void DtoCreateNestedContext(FuncDeclaration* fd);
|
||||
|
||||
/// Allocate space for variable accessed from nested function.
|
||||
void DtoNestedInit(VarDeclaration* vd);
|
||||
|
||||
/// Gets the context value for a call to a nested function or newing a nested
|
||||
/// class with arbitrary nesting.
|
||||
llvm::Value* DtoNestedContext(Loc loc, Dsymbol* sym);
|
||||
|
||||
/// Gets the DValue of a nested variable with arbitrary nesting.
|
||||
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd);
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/functions.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/nested.h"
|
||||
|
||||
#include "gen/logger.h"
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "gen/aa.h"
|
||||
#include "gen/functions.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/nested.h"
|
||||
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user