mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 07:00:46 +03:00
Emit debug info for variables that are used in nested functions
This commit is contained in:
parent
cedb4c0e68
commit
b8721a8515
7 changed files with 103 additions and 25 deletions
|
@ -361,6 +361,7 @@ struct VarDeclaration : Declaration
|
||||||
|
|
||||||
// debug description
|
// debug description
|
||||||
llvm::DIVariable debugVariable;
|
llvm::DIVariable debugVariable;
|
||||||
|
llvm::DISubprogram debugFunc;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -729,6 +729,15 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// give the 'nestArg' storage
|
||||||
|
if (f->fty.arg_nest)
|
||||||
|
{
|
||||||
|
LLValue *nestArg = irfunction->nestArg;
|
||||||
|
LLValue *val = DtoRawAlloca(nestArg->getType(), 0, "nestedFrame");
|
||||||
|
DtoStore(nestArg, val);
|
||||||
|
irfunction->nestArg = val;
|
||||||
|
}
|
||||||
|
|
||||||
// give arguments storage
|
// give arguments storage
|
||||||
// and debug info
|
// and debug info
|
||||||
if (fd->parameters)
|
if (fd->parameters)
|
||||||
|
|
|
@ -519,7 +519,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op)
|
||||||
DVarValue *var = lhs->isVar();
|
DVarValue *var = lhs->isVar();
|
||||||
VarDeclaration *varDecl = var ? var->var : 0;
|
VarDeclaration *varDecl = var ? var->var : 0;
|
||||||
if (global.params.symdebug && varDecl && varDecl->debugVariable)
|
if (global.params.symdebug && varDecl && varDecl->debugVariable)
|
||||||
DtoDwarfValue(rhs->getRVal(), lhs->isVar()->var);
|
DtoDwarfValue(lhs->getRVal(), varDecl);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/functions.h"
|
#include "gen/functions.h"
|
||||||
|
#include "gen/todebug.h"
|
||||||
|
|
||||||
#include "llvm/Analysis/ValueTracking.h"
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
@ -120,6 +121,10 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
|
||||||
return new DVarValue(astype, vd, val);
|
return new DVarValue(astype, vd, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLValue *dwarfValue = 0;
|
||||||
|
std::vector<LLValue*> dwarfAddr;
|
||||||
|
LLType *int64Ty = LLType::getInt64Ty(gIR->context());
|
||||||
|
|
||||||
// get the nested context
|
// get the nested context
|
||||||
LLValue* ctx = 0;
|
LLValue* ctx = 0;
|
||||||
if (irfunc->decl->isMember2())
|
if (irfunc->decl->isMember2())
|
||||||
|
@ -135,10 +140,15 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
|
||||||
#endif
|
#endif
|
||||||
ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
|
ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
|
||||||
}
|
}
|
||||||
else if (irfunc->nestedVar)
|
else if (irfunc->nestedVar) {
|
||||||
ctx = irfunc->nestedVar;
|
ctx = irfunc->nestedVar;
|
||||||
else
|
dwarfValue = ctx;
|
||||||
ctx = irfunc->nestArg;
|
} else {
|
||||||
|
ctx = DtoLoad(irfunc->nestArg);
|
||||||
|
dwarfValue = irfunc->nestArg;
|
||||||
|
if (global.params.symdebug)
|
||||||
|
dwarfOpDeref(dwarfAddr);
|
||||||
|
}
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
|
|
||||||
DtoCreateNestedContextType(vdparent->isFuncDeclaration());
|
DtoCreateNestedContextType(vdparent->isFuncDeclaration());
|
||||||
|
@ -174,21 +184,32 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
|
||||||
Logger::println("Same depth");
|
Logger::println("Same depth");
|
||||||
} else {
|
} else {
|
||||||
// Load frame pointer and index that...
|
// Load frame pointer and index that...
|
||||||
|
if (dwarfValue && global.params.symdebug) {
|
||||||
|
dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth);
|
||||||
|
dwarfOpDeref(dwarfAddr);
|
||||||
|
}
|
||||||
Logger::println("Lower depth");
|
Logger::println("Lower depth");
|
||||||
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
|
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
|
||||||
Logger::cout() << "Frame index: " << *val << '\n';
|
Logger::cout() << "Frame index: " << *val << '\n';
|
||||||
val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str());
|
val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str());
|
||||||
Logger::cout() << "Frame: " << *val << '\n';
|
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());
|
val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
|
||||||
Logger::cout() << "Addr: " << *val << '\n';
|
Logger::cout() << "Addr: " << *val << '\n';
|
||||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||||
if (vd->ir.irLocal->byref || byref) {
|
if (vd->ir.irLocal->byref || byref) {
|
||||||
val = DtoAlignedLoad(val);
|
val = DtoAlignedLoad(val);
|
||||||
|
//dwarfOpDeref(dwarfAddr);
|
||||||
Logger::cout() << "Was byref, now: " << *val << '\n';
|
Logger::cout() << "Was byref, now: " << *val << '\n';
|
||||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dwarfValue && global.params.symdebug)
|
||||||
|
DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr);
|
||||||
|
|
||||||
return new DVarValue(astype, vd, val);
|
return new DVarValue(astype, vd, val);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -283,7 +304,7 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
|
||||||
}
|
}
|
||||||
// otherwise, it may have gotten a context from the caller
|
// otherwise, it may have gotten a context from the caller
|
||||||
else if (irfunc->nestArg)
|
else if (irfunc->nestArg)
|
||||||
val = irfunc->nestArg;
|
val = DtoLoad(irfunc->nestArg);
|
||||||
// or just have a this argument
|
// or just have a this argument
|
||||||
else if (irfunc->thisArg)
|
else if (irfunc->thisArg)
|
||||||
{
|
{
|
||||||
|
@ -532,7 +553,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||||
// copy parent frame into beginning
|
// copy parent frame into beginning
|
||||||
if (nparelems)
|
if (nparelems)
|
||||||
{
|
{
|
||||||
LLValue* src = irfunction->nestArg;
|
LLValue* src = DtoLoad(irfunction->nestArg);
|
||||||
if (!src)
|
if (!src)
|
||||||
{
|
{
|
||||||
assert(irfunction->thisArg);
|
assert(irfunction->thisArg);
|
||||||
|
@ -594,7 +615,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||||
|
|
||||||
// copy parent frames into beginning
|
// copy parent frames into beginning
|
||||||
if (depth != 0) {
|
if (depth != 0) {
|
||||||
LLValue* src = irfunction->nestArg;
|
LLValue* src = DtoLoad(irfunction->nestArg);
|
||||||
if (!src) {
|
if (!src) {
|
||||||
assert(irfunction->thisArg);
|
assert(irfunction->thisArg);
|
||||||
assert(fd->isMember2());
|
assert(fd->isMember2());
|
||||||
|
@ -669,6 +690,12 @@ void DtoCreateNestedContext(FuncDeclaration* fd) {
|
||||||
vd->ir.irLocal->value = gep;
|
vd->ir.irLocal->value = gep;
|
||||||
vd->ir.irLocal->byref = false;
|
vd->ir.irLocal->byref = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (FuncDeclaration* parFunc = getParentFunc(fd, true)) {
|
||||||
// Propagate context arg properties if the context arg is passed on unmodified.
|
// Propagate context arg properties if the context arg is passed on unmodified.
|
||||||
|
|
|
@ -361,11 +361,14 @@ static llvm::DIType dwarfTypeDescription(Type* type, const char* c_name)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd)
|
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd, llvm::ArrayRef<LLValue*> addr)
|
||||||
{
|
{
|
||||||
Logger::println("D to dwarf local variable");
|
Logger::println("D to dwarf local variable");
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
if (gIR->func()->diSubprogram == vd->debugFunc) // ensure that the debug variable is created only once
|
||||||
|
return;
|
||||||
|
|
||||||
// get type description
|
// get type description
|
||||||
llvm::DIType TD = dwarfTypeDescription(vd->type, NULL);
|
llvm::DIType TD = dwarfTypeDescription(vd->type, NULL);
|
||||||
if ((llvm::MDNode*)TD == 0)
|
if ((llvm::MDNode*)TD == 0)
|
||||||
|
@ -380,15 +383,28 @@ void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd)
|
||||||
else
|
else
|
||||||
tag = DW_TAG_auto_variable;
|
tag = DW_TAG_auto_variable;
|
||||||
|
|
||||||
vd->debugVariable = gIR->dibuilder.createLocalVariable(
|
if (addr.empty()) {
|
||||||
tag, // tag
|
vd->debugVariable = gIR->dibuilder.createLocalVariable(
|
||||||
gIR->func()->diSubprogram, // context
|
tag, // tag
|
||||||
vd->toChars(), // name
|
gIR->func()->diSubprogram, // context
|
||||||
DtoDwarfFile(vd->loc), // file
|
vd->toChars(), // name
|
||||||
vd->loc.linnum, // line num
|
DtoDwarfFile(vd->loc), // file
|
||||||
TD, // type
|
vd->loc.linnum, // line num
|
||||||
true // preserve
|
TD, // type
|
||||||
);
|
true // preserve
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
vd->debugVariable = gIR->dibuilder.createComplexVariable(
|
||||||
|
tag, // tag
|
||||||
|
gIR->func()->diSubprogram, // context
|
||||||
|
vd->toChars(), // name
|
||||||
|
DtoDwarfFile(vd->loc), // file
|
||||||
|
vd->loc.linnum, // line num
|
||||||
|
TD, // type
|
||||||
|
addr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
vd->debugFunc = gIR->func()->diSubprogram;
|
||||||
|
|
||||||
// declare
|
// declare
|
||||||
dwarfDeclare(ll, vd->debugVariable);
|
dwarfDeclare(ll, vd->debugVariable);
|
||||||
|
@ -522,12 +538,9 @@ void DtoDwarfStopPoint(unsigned ln)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void DtoDwarfValue(LLValue* var, VarDeclaration* vd)
|
void DtoDwarfValue(LLValue *val, VarDeclaration* vd)
|
||||||
{
|
{
|
||||||
if (llvm::isa<llvm::AllocaInst>(vd->ir.irLocal->value) == 0)
|
llvm::Instruction *instr = gIR->dibuilder.insertDbgValueIntrinsic(val, 0, vd->debugVariable, gIR->scopebb());
|
||||||
return;
|
|
||||||
|
|
||||||
llvm::Instruction *instr = gIR->dibuilder.insertDbgValueIntrinsic(vd->ir.irLocal->value, 0, vd->debugVariable, gIR->scopebb());
|
|
||||||
instr->setDebugLoc(gIR->ir->getCurrentDebugLocation());
|
instr->setDebugLoc(gIR->ir->getCurrentDebugLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#ifndef DISABLE_DEBUG_INFO
|
#ifndef DISABLE_DEBUG_INFO
|
||||||
|
|
||||||
|
#include "gen/tollvm.h"
|
||||||
|
#include "gen/irstate.h"
|
||||||
|
|
||||||
void RegisterDwarfSymbols(llvm::Module* mod);
|
void RegisterDwarfSymbols(llvm::Module* mod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,14 +34,15 @@ void DtoDwarfFuncEnd(FuncDeclaration* fd);
|
||||||
|
|
||||||
void DtoDwarfStopPoint(unsigned ln);
|
void DtoDwarfStopPoint(unsigned ln);
|
||||||
|
|
||||||
void DtoDwarfValue(LLValue* var, VarDeclaration* vd);
|
void DtoDwarfValue(LLValue *val, VarDeclaration* vd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits all things necessary for making debug info for a local variable vd.
|
* Emits all things necessary for making debug info for a local variable vd.
|
||||||
* @param ll LLVM Value of the variable.
|
* @param ll LLVM Value of the variable.
|
||||||
* @param vd Variable declaration to emit debug info for.
|
* @param vd Variable declaration to emit debug info for.
|
||||||
*/
|
*/
|
||||||
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd);
|
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd,
|
||||||
|
llvm::ArrayRef<LLValue*> addr = llvm::ArrayRef<LLValue*>());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits all things necessary for making debug info for a global variable vd.
|
* Emits all things necessary for making debug info for a global variable vd.
|
||||||
|
@ -50,6 +54,30 @@ llvm::DIGlobalVariable DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclarati
|
||||||
|
|
||||||
void DtoDwarfModuleEnd();
|
void DtoDwarfModuleEnd();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void dwarfOpOffset(T &addr, LLStructType *type, int index)
|
||||||
|
{
|
||||||
|
uint64_t offset = gTargetData->getStructLayout(type)->getElementOffset(index);
|
||||||
|
LLType *int64Ty = LLType::getInt64Ty(gIR->context());
|
||||||
|
addr.push_back(LLConstantInt::get(int64Ty, llvm::DIBuilder::OpPlus));
|
||||||
|
addr.push_back(LLConstantInt::get(int64Ty, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void dwarfOpOffset(T &addr, LLValue *val, int index)
|
||||||
|
{
|
||||||
|
LLStructType *type = isaStruct(val->getType()->getContainedType(0));
|
||||||
|
assert(type);
|
||||||
|
dwarfOpOffset(addr, type, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void dwarfOpDeref(T &addr)
|
||||||
|
{
|
||||||
|
LLType *int64Ty = LLType::getInt64Ty(gIR->context());
|
||||||
|
addr.push_back(LLConstantInt::get(int64Ty, llvm::DIBuilder::OpDeref));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // DISABLE_DEBUG_INFO
|
#endif // DISABLE_DEBUG_INFO
|
||||||
|
|
||||||
|
|
|
@ -2553,7 +2553,7 @@ DValue* FuncExp::toElem(IRState* p)
|
||||||
)
|
)
|
||||||
cval = irfn->nestedVar;
|
cval = irfn->nestedVar;
|
||||||
else if (irfn->nestArg)
|
else if (irfn->nestArg)
|
||||||
cval = irfn->nestArg;
|
cval = DtoLoad(irfn->nestArg);
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
// TODO: should we enable that for D1 as well?
|
// TODO: should we enable that for D1 as well?
|
||||||
else if (irfn->thisArg)
|
else if (irfn->thisArg)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue