From b8721a85151abc93574c0dc66f73a1c70bbd52f4 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 3 Dec 2011 23:38:31 +0400 Subject: [PATCH] Emit debug info for variables that are used in nested functions --- dmd2/declaration.h | 1 + gen/functions.cpp | 9 +++++++++ gen/llvmhelpers.cpp | 2 +- gen/nested.cpp | 39 +++++++++++++++++++++++++++++++++------ gen/todebug.cpp | 43 ++++++++++++++++++++++++++++--------------- gen/todebug.h | 32 ++++++++++++++++++++++++++++++-- gen/toir.cpp | 2 +- 7 files changed, 103 insertions(+), 25 deletions(-) diff --git a/dmd2/declaration.h b/dmd2/declaration.h index ddf0758a..1c3431df 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -361,6 +361,7 @@ struct VarDeclaration : Declaration // debug description llvm::DIVariable debugVariable; + llvm::DISubprogram debugFunc; #endif }; diff --git a/gen/functions.cpp b/gen/functions.cpp index be8b1f11..71a17fe9 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -729,6 +729,15 @@ void DtoDefineFunction(FuncDeclaration* fd) #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 // and debug info if (fd->parameters) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index dc09cf97..c5903d2f 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -519,7 +519,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op) DVarValue *var = lhs->isVar(); VarDeclaration *varDecl = var ? var->var : 0; if (global.params.symdebug && varDecl && varDecl->debugVariable) - DtoDwarfValue(rhs->getRVal(), lhs->isVar()->var); + DtoDwarfValue(lhs->getRVal(), varDecl); #endif } diff --git a/gen/nested.cpp b/gen/nested.cpp index cdac766e..cc7a3f3f 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -6,6 +6,7 @@ #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/functions.h" +#include "gen/todebug.h" #include "llvm/Analysis/ValueTracking.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); } + LLValue *dwarfValue = 0; + std::vector dwarfAddr; + LLType *int64Ty = LLType::getInt64Ty(gIR->context()); + // get the nested context LLValue* ctx = 0; if (irfunc->decl->isMember2()) @@ -135,10 +140,15 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) #endif ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); } - else if (irfunc->nestedVar) + else if (irfunc->nestedVar) { ctx = irfunc->nestedVar; - else - ctx = irfunc->nestArg; + dwarfValue = ctx; + } else { + ctx = DtoLoad(irfunc->nestArg); + dwarfValue = irfunc->nestArg; + if (global.params.symdebug) + dwarfOpDeref(dwarfAddr); + } assert(ctx); DtoCreateNestedContextType(vdparent->isFuncDeclaration()); @@ -174,21 +184,32 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) 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 (vd->ir.irLocal->byref || 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 { @@ -283,7 +304,7 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) } // otherwise, it may have gotten a context from the caller else if (irfunc->nestArg) - val = irfunc->nestArg; + val = DtoLoad(irfunc->nestArg); // or just have a this argument else if (irfunc->thisArg) { @@ -532,7 +553,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { // copy parent frame into beginning if (nparelems) { - LLValue* src = irfunction->nestArg; + LLValue* src = DtoLoad(irfunction->nestArg); if (!src) { assert(irfunction->thisArg); @@ -594,7 +615,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { // copy parent frames into beginning if (depth != 0) { - LLValue* src = irfunction->nestArg; + LLValue* src = DtoLoad(irfunction->nestArg); if (!src) { assert(irfunction->thisArg); assert(fd->isMember2()); @@ -669,6 +690,12 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { vd->ir.irLocal->value = gep; vd->ir.irLocal->byref = false; } + + if (global.params.symdebug) { + LLSmallVector 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. diff --git a/gen/todebug.cpp b/gen/todebug.cpp index c47a399e..a00213fd 100644 --- a/gen/todebug.cpp +++ b/gen/todebug.cpp @@ -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 addr) { Logger::println("D to dwarf local variable"); LOG_SCOPE; + if (gIR->func()->diSubprogram == vd->debugFunc) // ensure that the debug variable is created only once + return; + // get type description llvm::DIType TD = dwarfTypeDescription(vd->type, NULL); if ((llvm::MDNode*)TD == 0) @@ -380,15 +383,28 @@ void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd) else tag = DW_TAG_auto_variable; - vd->debugVariable = gIR->dibuilder.createLocalVariable( - tag, // tag - gIR->func()->diSubprogram, // context - vd->toChars(), // name - DtoDwarfFile(vd->loc), // file - vd->loc.linnum, // line num - TD, // type - true // preserve - ); + if (addr.empty()) { + vd->debugVariable = gIR->dibuilder.createLocalVariable( + tag, // tag + gIR->func()->diSubprogram, // context + vd->toChars(), // name + DtoDwarfFile(vd->loc), // file + vd->loc.linnum, // line num + 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 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(vd->ir.irLocal->value) == 0) - return; - - llvm::Instruction *instr = gIR->dibuilder.insertDbgValueIntrinsic(vd->ir.irLocal->value, 0, vd->debugVariable, gIR->scopebb()); + llvm::Instruction *instr = gIR->dibuilder.insertDbgValueIntrinsic(val, 0, vd->debugVariable, gIR->scopebb()); instr->setDebugLoc(gIR->ir->getCurrentDebugLocation()); } diff --git a/gen/todebug.h b/gen/todebug.h index 8518da56..597be22d 100644 --- a/gen/todebug.h +++ b/gen/todebug.h @@ -3,6 +3,9 @@ #ifndef DISABLE_DEBUG_INFO +#include "gen/tollvm.h" +#include "gen/irstate.h" + void RegisterDwarfSymbols(llvm::Module* mod); /** @@ -31,14 +34,15 @@ void DtoDwarfFuncEnd(FuncDeclaration* fd); 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. * @param ll LLVM Value of the variable. * @param vd Variable declaration to emit debug info for. */ -void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd); +void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd, + llvm::ArrayRef addr = llvm::ArrayRef()); /** * 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(); +template +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 +void dwarfOpOffset(T &addr, LLValue *val, int index) +{ + LLStructType *type = isaStruct(val->getType()->getContainedType(0)); + assert(type); + dwarfOpOffset(addr, type, index); +} + +template +void dwarfOpDeref(T &addr) +{ + LLType *int64Ty = LLType::getInt64Ty(gIR->context()); + addr.push_back(LLConstantInt::get(int64Ty, llvm::DIBuilder::OpDeref)); +} + #endif // DISABLE_DEBUG_INFO diff --git a/gen/toir.cpp b/gen/toir.cpp index 533c60d1..5763ab5d 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -2553,7 +2553,7 @@ DValue* FuncExp::toElem(IRState* p) ) cval = irfn->nestedVar; else if (irfn->nestArg) - cval = irfn->nestArg; + cval = DtoLoad(irfn->nestArg); #if DMDV2 // TODO: should we enable that for D1 as well? else if (irfn->thisArg)