ldc/gen/dibuilder.cpp

790 lines
23 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- gen/dibuilder.h - Debug information builder -------------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/dibuilder.h"
#include "gen/irstate.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "ir/irtypeaggr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "enum.h"
#include "module.h"
#include "mtype.h"
////////////////////////////////////////////////////////////////////////////////
// get the module the symbol is in, or - for template instances - the current module
Module *ldc::DIBuilder::getDefinedModule(Dsymbol *s)
{
// templates are defined in current module
if (DtoIsTemplateInstance(s, true))
{
return IR->dmodule;
}
// array operations as well
else if (FuncDeclaration* fd = s->isFuncDeclaration())
{
if (fd->isArrayOp == 1)
return IR->dmodule;
}
// otherwise use the symbol's module
return s->getModule();
}
////////////////////////////////////////////////////////////////////////////////
ldc::DIBuilder::DIBuilder(IRState *const IR, llvm::Module &M)
: IR(IR), DBuilder(M)
{
}
llvm::LLVMContext &ldc::DIBuilder::getContext()
{
return IR->context();
}
llvm::DIDescriptor ldc::DIBuilder::GetCurrentScope()
{
IrFunction *fn = IR->func();
if (fn->diLexicalBlocks.empty())
{
assert(static_cast<llvm::MDNode *>(fn->diSubprogram) != 0);
return fn->diSubprogram;
}
return fn->diLexicalBlocks.top();
}
void ldc::DIBuilder::Declare(llvm::Value *var, llvm::DIVariable divar)
{
llvm::Instruction *instr = DBuilder.insertDeclare(var, divar, IR->scopebb());
instr->setDebugLoc(IR->ir->getCurrentDebugLocation());
}
llvm::DIFile ldc::DIBuilder::CreateFile(Loc loc)
{
llvm::SmallString<128> path(loc.filename ? loc.filename : "");
llvm::sys::fs::make_absolute(path);
return DBuilder.createFile(
llvm::sys::path::filename(path),
llvm::sys::path::parent_path(path)
);
}
llvm::DIType ldc::DIBuilder::CreateBasicType(Type *type)
{
using namespace llvm::dwarf;
Type *t = type->toBasetype();
llvm::Type *T = DtoType(type);
// find encoding
unsigned Encoding;
switch (t->ty)
{
case Tbool:
Encoding = DW_ATE_boolean;
break;
case Tchar:
case Twchar:
case Tdchar:
Encoding = type->isunsigned() ? DW_ATE_unsigned_char
: DW_ATE_signed_char;
break;
case Tint8:
case Tint16:
case Tint32:
case Tint64:
case Tint128:
Encoding = DW_ATE_signed;
break;
case Tuns8:
case Tuns16:
case Tuns32:
case Tuns64:
case Tuns128:
Encoding = DW_ATE_unsigned;
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
Encoding = DW_ATE_float;
break;
case Timaginary32:
case Timaginary64:
case Timaginary80:
Encoding = DW_ATE_imaginary_float;
break;
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
Encoding = DW_ATE_complex_float;
break;
default:
llvm_unreachable("Unsupported basic type for debug info in DIBuilder::CreateBasicType");
}
return DBuilder.createBasicType(
type->toChars(), // name
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
Encoding
);
}
llvm::DIType ldc::DIBuilder::CreateEnumType(Type *type)
{
llvm::Type *T = DtoType(type);
assert(type->ty == Tenum && "only enums allowed for debug info in dwarfEnumType");
TypeEnum *te = static_cast<TypeEnum *>(type);
llvm::SmallVector<llvm::Value *, 8> subscripts;
for (Dsymbols::iterator I = te->sym->members->begin(),
E = te->sym->members->end();
I != E; ++I)
{
EnumMember *em = (*I)->isEnumMember();
llvm::StringRef Name(em->toChars());
uint64_t Val = em->value->toInteger();
llvm::Value *Subscript = DBuilder.createEnumerator(Name, Val);
subscripts.push_back(Subscript);
}
llvm::StringRef Name = te->toChars();
unsigned LineNumber = te->sym->loc.linnum;
llvm::DIFile File = CreateFile(te->sym->loc);
return DBuilder.createEnumerationType(
llvm::DICompileUnit(GetCU()),
Name,
File,
LineNumber,
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
DBuilder.getOrCreateArray(subscripts) // subscripts
#if LDC_LLVM_VER >= 302
, CreateTypeDescription(te->sym->memtype, NULL)
#endif
);
}
llvm::DIType ldc::DIBuilder::CreatePointerType(Type *type)
{
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
assert(t->ty == Tpointer && "Only pointers allowed for debug info in DIBuilder::CreatePointerType");
// find base type
Type *nt = t->nextOf();
llvm::DIType basetype = CreateTypeDescription(nt, NULL);
return DBuilder.createPointerType(
basetype,
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
type->toChars() // name
);
}
llvm::DIType ldc::DIBuilder::CreateVectorType(Type *type)
{
LLType* T = DtoType(type);
Type* t = type->toBasetype();
assert(t->ty == Tvector && "Only vectors allowed for debug info in DIBuilder::CreateVectorType");
TypeVector *tv = static_cast<TypeVector *>(t);
Type *te = tv->elementType();
int64_t Dim = tv->size(Loc()) / te->size(Loc());
llvm::Value *subscripts[] =
{
DBuilder.getOrCreateSubrange(0, Dim)
};
llvm::DIType basetype = CreateTypeDescription(te, NULL);
return DBuilder.createVectorType(
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
basetype, // element type
DBuilder.getOrCreateArray(subscripts) // subscripts
);
}
llvm::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
llvm::DIFile file,
const char* c_name,
unsigned offset)
{
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
// find base type
llvm::DIType basetype = CreateTypeDescription(t, NULL, true);
return DBuilder.createMemberType(
llvm::DICompileUnit(GetCU()),
c_name, // name
file, // file
linnum, // line number
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
offset*8, // offset (bits)
//FIXME: need flags?
0, // flags
basetype // derived from
);
}
void ldc::DIBuilder::AddBaseFields(ClassDeclaration *sd, llvm::DIFile file,
std::vector<llvm::Value*> &elems)
{
if (sd->baseClass)
{
AddBaseFields(sd->baseClass, file, elems);
}
size_t narr = sd->fields.dim;
elems.reserve(narr);
for (VarDeclarations::iterator I = sd->fields.begin(),
E = sd->fields.end();
I != E; ++I)
{
VarDeclaration* vd = *I;
elems.push_back(CreateMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset));
}
}
llvm::DIType ldc::DIBuilder::CreateCompositeType(Type *type)
{
Type* t = type->toBasetype();
assert((t->ty == Tstruct || t->ty == Tclass) &&
"Unsupported type for debug info in DIBuilder::CreateCompositeType");
AggregateDeclaration* sd;
if (t->ty == Tstruct)
{
TypeStruct* ts = static_cast<TypeStruct*>(t);
sd = ts->sym;
}
else
{
TypeClass* tc = static_cast<TypeClass*>(t);
sd = tc->sym;
}
assert(sd);
// Use the actual type associated with the declaration, ignoring any
// const/… wrappers.
LLType *T = DtoType(sd->type);
IrTypeAggr *ir = sd->type->irtype->isAggr();
assert(ir);
if (static_cast<llvm::MDNode *>(ir->diCompositeType) != 0)
return ir->diCompositeType;
// if we don't know the aggregate's size, we don't know enough about it
// to provide debug info. probably a forward-declared struct?
if (sd->sizeok == SIZEOKnone)
#if LDC_LLVM_VER >= 304
return DBuilder.createUnspecifiedType(sd->toChars());
#else
return llvm::DICompositeType(NULL);
#endif
// elements
std::vector<llvm::Value *> elems;
// defaults
llvm::StringRef name = sd->toChars();
unsigned linnum = sd->loc.linnum;
llvm::DICompileUnit CU(GetCU());
assert(CU && CU.Verify() && "Compilation unit missing or corrupted");
llvm::DIFile file = CreateFile(sd->loc);
llvm::DIType derivedFrom;
// set diCompositeType to handle recursive types properly
unsigned tag = (t->ty == Tstruct) ? llvm::dwarf::DW_TAG_structure_type
: llvm::dwarf::DW_TAG_class_type;
ir->diCompositeType = DBuilder.createForwardDecl(tag, name,
#if LDC_LLVM_VER >= 302
CU,
#endif
file, linnum);
if (!sd->isInterfaceDeclaration()) // plain interfaces don't have one
{
if (t->ty == Tstruct)
{
elems.reserve(sd->fields.dim);
for (VarDeclarations::iterator I = sd->fields.begin(),
E = sd->fields.end();
I != E; ++I)
{
VarDeclaration* vd = *I;
llvm::DIType dt = CreateMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset);
elems.push_back(dt);
}
}
else
{
ClassDeclaration *classDecl = sd->isClassDeclaration();
AddBaseFields(classDecl, file, elems);
if (classDecl->baseClass)
derivedFrom = CreateCompositeType(classDecl->baseClass->getType());
}
}
llvm::DIArray elemsArray = DBuilder.getOrCreateArray(elems);
llvm::DIType ret;
if (t->ty == Tclass) {
ret = DBuilder.createClassType(
CU, // compile unit where defined
name, // name
file, // file where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
0, // offset in bits,
llvm::DIType::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
elemsArray
);
} else {
ret = DBuilder.createStructType(
CU, // compile unit where defined
name, // name
file, // file where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
llvm::DIType::FlagFwdDecl, // flags
#if LDC_LLVM_VER >= 303
derivedFrom, // DerivedFrom
#endif
elemsArray
);
}
ir->diCompositeType.replaceAllUsesWith(ret);
ir->diCompositeType = ret;
return ret;
}
llvm::DIType ldc::DIBuilder::CreateArrayType(Type *type)
{
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
assert(t->ty == Tarray && "Only arrays allowed for debug info in DIBuilder::CreateArrayType");
llvm::DIFile file = CreateFile(Loc(IR->dmodule, 0));
llvm::Value *elems[] = {
CreateMemberType(0, Type::tsize_t, file, "length", 0),
CreateMemberType(0, t->nextOf()->pointerTo(), file, "ptr",
global.params.is64bit ? 8 : 4)
};
return DBuilder.createStructType
(
llvm::DICompileUnit(GetCU()),
llvm::StringRef(), // Name TODO: Really no name for arrays? t->toChars()?
file, // File
0, // LineNo
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
0, // What here?
#if LDC_LLVM_VER >= 303
llvm::DIType(), // DerivedFrom
#endif
DBuilder.getOrCreateArray(elems)
);
}
llvm::DIType ldc::DIBuilder::CreateSArrayType(Type *type)
{
llvm::Type *T = DtoType(type);
Type *t = type->toBasetype();
// find base type
llvm::SmallVector<llvm::Value *, 8> subscripts;
while (t->ty == Tsarray)
{
TypeSArray *tsa = static_cast<TypeSArray *>(t);
int64_t Count = tsa->dim->toInteger();
llvm::Value *subscript = DBuilder.getOrCreateSubrange(0, Count-1);
subscripts.push_back(subscript);
t = t->nextOf();
}
llvm::DIType basetype = CreateTypeDescription(t, NULL);
return DBuilder.createArrayType(
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
basetype, // element type
DBuilder.getOrCreateArray(subscripts) // subscripts
);
}
llvm::DIType ldc::DIBuilder::CreateAArrayType(Type *type)
{
// FIXME: Implement
#if LDC_LLVM_VER >= 304
return DBuilder.createUnspecifiedType(type->toChars());
#else
return llvm::DIType(NULL);
#endif
}
////////////////////////////////////////////////////////////////////////////////
ldc::DIFunctionType ldc::DIBuilder::CreateFunctionType(Type *type)
{
TypeFunction *t = static_cast<TypeFunction*>(type);
Type *retType = t->next;
llvm::DIFile file = CreateFile(Loc(IR->dmodule, 0));
// Create "dummy" subroutine type for the return type
llvm::SmallVector<llvm::Value*, 16> Elts;
Elts.push_back(CreateTypeDescription(retType, NULL, true));
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
return DBuilder.createSubroutineType(file, EltTypeArray);
}
ldc::DIFunctionType ldc::DIBuilder::CreateDelegateType(Type *type)
{
// FIXME: Implement
TypeDelegate *t = static_cast<TypeDelegate*>(type);
llvm::DIFile file = CreateFile(Loc(IR->dmodule, 0));
// Create "dummy" subroutine type for the return type
llvm::SmallVector<llvm::Value*, 16> Elts;
Elts.push_back(
#if LDC_LLVM_VER >= 304
DBuilder.createUnspecifiedType(type->toChars())
#else
llvm::DIType(NULL)
#endif
);
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
return DBuilder.createSubroutineType(file, EltTypeArray);
}
////////////////////////////////////////////////////////////////////////////////
llvm::DIType ldc::DIBuilder::CreateTypeDescription(Type* type,
const char* c_name,
bool derefclass)
{
Type *t = type->toBasetype();
if (derefclass && t->ty == Tclass)
{
type = type->pointerTo();
t = type->toBasetype();
}
if (t->ty == Tvoid || t->ty == Tnull)
#if LDC_LLVM_VER >= 304
return DBuilder.createUnspecifiedType(t->toChars());
#else
return llvm::DIType(NULL);
#endif
else if (t->isintegral() || t->isfloating())
{
if (t->ty == Tvector)
return CreateVectorType(type);
if (type->ty == Tenum)
return CreateEnumType(type);
return CreateBasicType(type);
}
else if (t->ty == Tpointer)
return CreatePointerType(type);
else if (t->ty == Tarray)
return CreateArrayType(type);
else if (t->ty == Tsarray)
return CreateSArrayType(type);
else if (t->ty == Taarray)
return CreateAArrayType(type);
else if (t->ty == Tstruct || t->ty == Tclass)
return CreateCompositeType(type);
else if (t->ty == Tfunction)
return CreateFunctionType(type);
else if (t->ty == Tdelegate)
return CreateDelegateType(type);
// Crash if the type is not supported.
llvm_unreachable("Unsupported type in debug info");
}
////////////////////////////////////////////////////////////////////////////////
void ldc::DIBuilder::EmitCompileUnit(Module *m)
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf compile_unit");
LOG_SCOPE;
// prepare srcpath
llvm::SmallString<128> srcpath(m->srcfile->name->toChars());
llvm::sys::fs::make_absolute(srcpath);
#if LDC_LLVM_VER >= 304
CUNode =
#endif
DBuilder.createCompileUnit(
global.params.symdebug == 2 ? llvm::dwarf::DW_LANG_C
: llvm::dwarf::DW_LANG_D,
llvm::sys::path::filename(srcpath),
llvm::sys::path::parent_path(srcpath),
"LDC (http://wiki.dlang.org/LDC)",
false, // isOptimized TODO
llvm::StringRef(), // Flags TODO
1 // Runtime Version TODO
);
#if LDC_LLVM_VER < 304
CUNode = DBuilder.getCU();
#endif
}
llvm::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd)
{
if (!global.params.symdebug)
return llvm::DISubprogram();
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
llvm::DICompileUnit CU(GetCU());
assert(CU && CU.Verify() && "Compilation unit missing or corrupted in DIBuilder::EmitSubProgram");
llvm::DIFile file = CreateFile(fd->loc);
// Create subroutine type
ldc::DIFunctionType DIFnType = CreateFunctionType(static_cast<TypeFunction*>(fd->type));
// FIXME: duplicates ?
return DBuilder.createFunction(
CU, // context
fd->toPrettyChars(), // name
fd->mangleExact(), // linkage name
file, // file
fd->loc.linnum, // line no
DIFnType, // type
fd->protection == PROTprivate, // is local to unit
IR->dmodule == getDefinedModule(fd), // isdefinition
fd->loc.linnum, // FIXME: scope line
0, // Flags
false, // isOptimized
fd->ir.irFunc->func
);
}
llvm::DISubprogram ldc::DIBuilder::EmitSubProgramInternal(llvm::StringRef prettyname,
llvm::StringRef mangledname)
{
if (!global.params.symdebug)
return llvm::DISubprogram();
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
llvm::DIFile file(CreateFile(Loc(IR->dmodule, 0)));
// Create "dummy" subroutine type for the return type
llvm::SmallVector<llvm::Value *, 1> Elts;
#if LDC_LLVM_VER >= 304
Elts.push_back(DBuilder.createUnspecifiedType(prettyname));
#else
Elts.push_back(llvm::DIType(NULL));
#endif
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
ldc::DIFunctionType DIFnType = DBuilder.createSubroutineType(file, EltTypeArray);
// FIXME: duplicates ?
return DBuilder.createFunction(
llvm::DIDescriptor(file), // context
prettyname, // name
mangledname, // linkage name
file, // file
0, // line no
DIFnType, // return type. TODO: fill it up
true, // is local to unit
true, // isdefinition
0 // FIXME: scope line
);
}
void ldc::DIBuilder::EmitFuncStart(FuncDeclaration *fd)
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf funcstart");
LOG_SCOPE;
assert(static_cast<llvm::MDNode *>(fd->ir.irFunc->diSubprogram) != 0);
EmitStopPoint(fd->loc.linnum);
}
void ldc::DIBuilder::EmitFuncEnd(FuncDeclaration *fd)
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf funcend");
LOG_SCOPE;
assert(static_cast<llvm::MDNode *>(fd->ir.irFunc->diSubprogram) != 0);
}
void ldc::DIBuilder::EmitBlockStart(Loc loc)
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf block start");
LOG_SCOPE;
llvm::DILexicalBlock block = DBuilder.createLexicalBlock(
GetCurrentScope(), // scope
CreateFile(loc), // file
loc.linnum, // line
0 // column
#if LDC_LLVM_VER >= 305
, 0 // DWARF path discriminator value
#endif
);
IR->func()->diLexicalBlocks.push(block);
EmitStopPoint(loc.linnum);
}
void ldc::DIBuilder::EmitBlockEnd()
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf block end");
LOG_SCOPE;
IrFunction *fn = IR->func();
assert(!fn->diLexicalBlocks.empty());
fn->diLexicalBlocks.pop();
}
void ldc::DIBuilder::EmitStopPoint(unsigned ln)
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf stoppoint at line %u", ln);
LOG_SCOPE;
llvm::DebugLoc loc = llvm::DebugLoc::get(ln, 0, GetCurrentScope());
IR->ir->SetCurrentDebugLocation(loc);
}
void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd)
{
if (!global.params.symdebug || !vd->debugVariable)
return;
llvm::Instruction *instr = DBuilder.insertDbgValueIntrinsic(val, 0, vd->debugVariable, IR->scopebb());
instr->setDebugLoc(IR->ir->getCurrentDebugLocation());
}
void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
llvm::ArrayRef<llvm::Value *> addr)
{
if (!global.params.symdebug)
return;
Logger::println("D to dwarf local variable");
LOG_SCOPE;
if (IR->func()->diSubprogram == vd->debugFunc) // ensure that the debug variable is created only once
return;
// get type description
llvm::DIType TD = CreateTypeDescription(vd->type, NULL, true);
if (static_cast<llvm::MDNode *>(TD) == 0)
return; // unsupported
// get variable description
assert(!vd->isDataseg() && "static variable");
unsigned tag;
if (vd->isParameter())
tag = llvm::dwarf::DW_TAG_arg_variable;
else
tag = llvm::dwarf::DW_TAG_auto_variable;
if (addr.empty()) {
vd->debugVariable = DBuilder.createLocalVariable(
tag, // tag
GetCurrentScope(), // scope
vd->toChars(), // name
CreateFile(vd->loc), // file
vd->loc.linnum, // line num
TD, // type
true // preserve
);
} else {
vd->debugVariable = DBuilder.createComplexVariable(
tag, // tag
GetCurrentScope(), // scope
vd->toChars(), // name
CreateFile(vd->loc), // file
vd->loc.linnum, // line num
TD, // type
addr
);
}
vd->debugFunc = IR->func()->diSubprogram;
// declare
Declare(ll, vd->debugVariable);
}
llvm::DIGlobalVariable ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *ll, VarDeclaration *vd)
{
if (!global.params.symdebug)
return llvm::DIGlobalVariable();
Logger::println("D to dwarf global_variable");
LOG_SCOPE;
assert(vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init));
return DBuilder.createGlobalVariable(
vd->toChars(), // name
#if LDC_LLVM_VER >= 303
vd->mangle(), // linkage name
#endif
CreateFile(vd->loc), // file
vd->loc.linnum, // line num
CreateTypeDescription(vd->type, NULL), // type
vd->protection == PROTprivate, // is local to unit
ll // value
);
}
void ldc::DIBuilder::EmitModuleEnd()
{
if (!global.params.symdebug)
return;
DBuilder.finalize();
}