view gen/todebug.cpp @ 1047:6bb04dbee21f

Some calling convention work for x86-64: - Implement x86-64 extern(C), hopefully correctly. - Tried to be a bit smarter about extern(D) while I was there. Interestingly, this code seems to be generating more efficient code than gcc and llvm-gcc in some edge cases, like returning a `{ [7 x i8] }` loaded from a stack slot from an extern(C) function. (gcc generates 7 1-byte loads, while this code generates a 4-byte, a 2-byte and a 1-byte load) I also added some changes to make sure structs being returned from functions or passed in as parameters are stored in memory where the rest of the backend seems to expect them to be. These should be removed when support for first-class aggregates improves.
author Frits van Bommel <fvbommel wxs.nl>
date Fri, 06 Mar 2009 16:00:47 +0100
parents ff22650d0ca3
children f0b6549055ab 186d44690036
line wrap: on
line source

#include "gen/llvm.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/System/Path.h"

#include "declaration.h"
#include "module.h"
#include "mars.h"

#include "gen/todebug.h"
#include "gen/irstate.h"
#include "gen/tollvm.h"
#include "gen/logger.h"
#include "gen/llvmhelpers.h"

#include "ir/irmodule.h"

using namespace llvm::dwarf;

#define DBG_NULL    ( LLConstant::getNullValue(DBG_TYPE) )
#define DBG_TYPE    ( getPtrToType(llvm::StructType::get(NULL,NULL)) )
#define DBG_CAST(X) ( llvm::ConstantExpr::getBitCast(X, DBG_TYPE) )

#define DBG_TAG(X)  ( llvm::ConstantExpr::getAdd( DtoConstUint( X ), DtoConstUint( llvm::LLVMDebugVersion ) ) )

//////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Emits a global variable, LLVM Dwarf style, only declares.
 * @param type Type of variable.
 * @param name Name.
 * @return The global variable.
 */
static LLGlobalVariable* emitDwarfGlobalDecl(const LLStructType* type, const char* name, bool linkonce=false)
{
    LLGlobalValue::LinkageTypes linkage = linkonce ? LLGlobalValue::LinkOnceLinkage : LLGlobalValue::InternalLinkage;
    LLGlobalVariable* gv = new LLGlobalVariable(type, true, linkage, NULL, name, gIR->module);
    gv->setSection("llvm.metadata");
    return gv;
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIAnchor getDwarfAnchor(dwarf_constants c)
{
    switch (c)
    {
    case DW_TAG_compile_unit:
        return gIR->difactory.GetOrCreateCompileUnitAnchor();
    case DW_TAG_variable:
        return gIR->difactory.GetOrCreateGlobalVariableAnchor();
    case DW_TAG_subprogram:
        return gIR->difactory.GetOrCreateSubprogramAnchor();
    default:
        assert(0);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static const llvm::StructType* getDwarfCompileUnitType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.compile_unit.type"));
}

static const llvm::StructType* getDwarfSubProgramType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.subprogram.type"));
}

static const llvm::StructType* getDwarfVariableType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.variable.type"));
}

static const llvm::StructType* getDwarfDerivedTypeType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.derivedtype.type"));
}

static const llvm::StructType* getDwarfBasicTypeType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.basictype.type"));
}

static const llvm::StructType* getDwarfCompositeTypeType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.compositetype.type"));
}

static const llvm::StructType* getDwarfGlobalVariableType() {
    return isaStruct(gIR->module->getTypeByName("llvm.dbg.global_variable.type"));
}

//////////////////////////////////////////////////////////////////////////////////////////////////

// get the module the symbol is in, or - for template instances - the current module
static Module* getDefinedModule(Dsymbol* s)
{
    if (!DtoIsTemplateInstance(s))
        return s->getModule();
    else
	return gIR->dmodule;
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIType dwarfTypeDescription_impl(Type* type, llvm::DICompileUnit cu, const char* c_name);
static llvm::DIType dwarfTypeDescription(Type* type, llvm::DICompileUnit cu, const char* c_name);

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIBasicType dwarfBasicType(Type* type, llvm::DICompileUnit compileUnit)
{
    Type* t = type->toBasetype();
    const LLType* T = DtoType(type);

    // find encoding
    unsigned id;
    if (t->isintegral())
    {
        if (type->isunsigned())
            id = DW_ATE_unsigned;
        else
            id = DW_ATE_signed;
    }
    else if (t->isfloating())
    {
        id = DW_ATE_float;
    }
    else
    {
        assert(0 && "unsupported basictype for debug info");
    }

    return gIR->difactory.CreateBasicType(
        compileUnit, // context
        type->toChars(), // name
        llvm::DICompileUnit(NULL), // compile unit
        0, // line number
        getTypeBitSize(T), // size (bits)
        getABITypeAlign(T)*8, // align (bits)
        0, // offset (bits)
//FIXME: need flags?
        0, // flags
        id // encoding
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIDerivedType dwarfDerivedType(Type* type, llvm::DICompileUnit compileUnit)
{
    const LLType* T = DtoType(type);
    Type* t = type->toBasetype();

    assert(t->ty == Tpointer && "unsupported derivedtype for debug info, only pointers allowed");

    // find base type
    llvm::DIType basetype;
    Type* nt = t->nextOf();
    basetype = dwarfTypeDescription_impl(nt, compileUnit, NULL);
    if (nt->ty == Tvoid)
        basetype = llvm::DIType(NULL);

    return gIR->difactory.CreateDerivedType(
        DW_TAG_pointer_type, // tag
        compileUnit, // context
        "", // name
        llvm::DICompileUnit(NULL), // compile unit
        0, // line number
        getTypeBitSize(T), // size (bits)
        getABITypeAlign(T)*8, // align (bits)
        0, // offset (bits)
//FIXME: need flags?
        0, // flags
        basetype // derived from
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIDerivedType dwarfMemberType(unsigned linnum, Type* type, llvm::DICompileUnit compileUnit, llvm::DICompileUnit definedCU, const char* c_name, unsigned offset)
{
    const LLType* T = DtoType(type);
    Type* t = type->toBasetype();

    // find base type
    llvm::DIType basetype;
    basetype = dwarfTypeDescription(t, compileUnit, NULL);
    if (t->ty == Tvoid)
        basetype = llvm::DIType(NULL);

    return gIR->difactory.CreateDerivedType(
        DW_TAG_member, // tag
        compileUnit, // context
        c_name, // name
        definedCU, // compile unit
        linnum, // line number
        getTypeBitSize(T), // size (bits)
        getABITypeAlign(T)*8, // align (bits)
        offset*8, // offset (bits)
//FIXME: need flags?
        0, // flags
        basetype // derived from
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

//FIXME: This does not use llvm's DIFactory as it can't 
//   handle recursive types properly.
static llvm::DICompositeType dwarfCompositeType(Type* type, llvm::DICompileUnit compileUnit)
{
    const LLType* T = DtoType(type);
    Type* t = type->toBasetype();

    // defaults
    LLConstant* name = getNullPtr(getVoidPtrType());
    LLGlobalVariable* members = NULL;
    unsigned linnum = 0;
    llvm::DICompileUnit definedCU;

    // prepare tag and members
    unsigned tag;

    // declare final global variable
    LLGlobalVariable* gv = NULL;

    // dynamic array
    if (t->ty == Tarray)
    {
        tag = DW_TAG_structure_type;

        LLGlobalVariable* len = dwarfMemberType(0, Type::tsize_t, compileUnit, llvm::DICompileUnit(NULL), "length", 0).getGV();
        assert(len);
        LLGlobalVariable* ptr = dwarfMemberType(0, t->nextOf()->pointerTo(), compileUnit, llvm::DICompileUnit(NULL), "ptr", global.params.is64bit?8:4).getGV();
        assert(ptr);

        const LLArrayType* at = LLArrayType::get(DBG_TYPE, 2);

        std::vector<LLConstant*> elems(2);
        elems[0] = DBG_CAST(len);
        elems[1] = DBG_CAST(ptr);

        LLConstant* ca = LLConstantArray::get(at, elems);
        members = new LLGlobalVariable(ca->getType(), true, LLGlobalValue::InternalLinkage, ca, ".array", gIR->module);
        members->setSection("llvm.metadata");

        name = DtoConstStringPtr(t->toChars(), "llvm.metadata");
    }

    // struct/class
    else if (t->ty == Tstruct || t->ty == Tclass)
    {
        AggregateDeclaration* sd;
        if (t->ty == Tstruct)
        {
            TypeStruct* ts = (TypeStruct*)t;
            sd = ts->sym;
        }
        else
        {
            TypeClass* tc = (TypeClass*)t;
            sd = tc->sym;
        }
        assert(sd);

        // 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 == 0)
            return llvm::DICompositeType(NULL);

        IrStruct* ir = sd->ir.irStruct;
        assert(ir);
        if (!ir->diCompositeType.isNull())
            return ir->diCompositeType;

        // set to handle recursive types properly
        gv = emitDwarfGlobalDecl(getDwarfCompositeTypeType(), "llvm.dbg.compositetype");
        // set bogus initializer to satisfy asserts in DICompositeType constructor
        gv->setInitializer(LLConstant::getNullValue(getDwarfCompositeTypeType()));
        ir->diCompositeType = llvm::DICompositeType(gv);

        tag = DW_TAG_structure_type;

        name = DtoConstStringPtr(sd->toChars(), "llvm.metadata");
        linnum = sd->loc.linnum;
        definedCU = DtoDwarfCompileUnit(getDefinedModule(sd));

        std::vector<LLConstant*> elems;
        if (!ir->aggrdecl->isInterfaceDeclaration()) // plain interfaces don't have one
        {
            std::vector<VarDeclaration*>& arr = ir->varDecls;
            size_t narr = arr.size();
            elems.reserve(narr);
            for (int k=0; k<narr; k++)
            {
                VarDeclaration* vd = arr[k];
                assert(vd);

                LLGlobalVariable* ptr = dwarfMemberType(vd->loc.linnum, vd->type, compileUnit, definedCU, vd->toChars(), vd->offset).getGV();
                elems.push_back(DBG_CAST(ptr));
            }
        }

        const LLArrayType* at = LLArrayType::get(DBG_TYPE, elems.size());
        LLConstant* ca = LLConstantArray::get(at, elems);
        members = new LLGlobalVariable(ca->getType(), true, LLGlobalValue::InternalLinkage, ca, ".array", gIR->module);
        members->setSection("llvm.metadata");
    }

    // unsupported composite type
    else
    {
        assert(0 && "unsupported compositetype for debug info");
    }

    std::vector<LLConstant*> vals(11);

    // tag
    vals[0] = DBG_TAG(tag);

    // context
    vals[1] = DBG_CAST(compileUnit.getGV());

    // name
    vals[2] = name;

    // compile unit where defined
    if (definedCU.getGV())
        vals[3] = DBG_CAST(definedCU.getGV());
    else
        vals[3] = DBG_NULL;

    // line number where defined
    vals[4] = DtoConstInt(linnum);

    // size in bits
    vals[5] = LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false);

    // alignment in bits
    vals[6] = LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false);

    // offset in bits
    vals[7] = LLConstantInt::get(LLType::Int64Ty, 0, false);

    // FIXME: dont know what this is
    vals[8] = DtoConstUint(0);

    // FIXME: ditto
    vals[9] = DBG_NULL;

    // members array
    if (members)
        vals[10] = DBG_CAST(members);
    else
        vals[10] = DBG_NULL;

    // set initializer
    if (!gv)
        gv = emitDwarfGlobalDecl(getDwarfCompositeTypeType(), "llvm.dbg.compositetype");
    LLConstant* initia = LLConstantStruct::get(getDwarfCompositeTypeType(), vals);
    gv->setInitializer(initia);

    return llvm::DICompositeType(gv);
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIGlobalVariable dwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd)
{
#if DMDV2
    assert(vd->isDataseg() || (vd->storage_class & (STCconst | STCinvariant) && vd->init));
#else
    assert(vd->isDataseg());
#endif
    llvm::DICompileUnit compileUnit = DtoDwarfCompileUnit(gIR->dmodule);

    return gIR->difactory.CreateGlobalVariable(
        compileUnit, // context
        vd->mangle(), // name
        vd->toPrettyChars(), // displayname
        vd->toChars(), // linkage name
        DtoDwarfCompileUnit(getDefinedModule(vd)), // compile unit
        vd->loc.linnum, // line num
        dwarfTypeDescription_impl(vd->type, compileUnit, NULL), // type
        vd->protection == PROTprivate, // is local to unit
        getDefinedModule(vd) == gIR->dmodule, // is definition
        ll // value
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIVariable dwarfVariable(VarDeclaration* vd, llvm::DIType type)
{
    assert(!vd->isDataseg() && "static variable");

    unsigned tag;
    if (vd->isParameter())
        tag = DW_TAG_arg_variable;
    else
        tag = DW_TAG_auto_variable;

    return gIR->difactory.CreateVariable(
        tag, // tag
        gIR->func()->diSubprogram, // context
        vd->toChars(), // name
        DtoDwarfCompileUnit(getDefinedModule(vd)), // compile unit
        vd->loc.linnum, // line num
        type // type
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static void dwarfDeclare(LLValue* var, llvm::DIVariable divar)
{
    gIR->difactory.InsertDeclare(var, divar, gIR->scopebb());
}

//////////////////////////////////////////////////////////////////////////////////////////////////

static llvm::DIType dwarfTypeDescription_impl(Type* type, llvm::DICompileUnit cu, const char* c_name)
{
    Type* t = type->toBasetype();
    if (t->ty == Tvoid)
        return llvm::DIType(NULL);
    else if (t->isintegral() || t->isfloating())
        return dwarfBasicType(type, cu);
    else if (t->ty == Tpointer)
        return dwarfDerivedType(type, cu);
    else if (t->ty == Tarray || t->ty == Tstruct || t->ty == Tclass)
        return dwarfCompositeType(type, cu);

    return llvm::DIType(NULL);
}

static llvm::DIType dwarfTypeDescription(Type* type, llvm::DICompileUnit cu, const char* c_name)
{
    Type* t = type->toBasetype();
    if (t->ty == Tclass)
        return dwarfTypeDescription_impl(type->pointerTo(), cu, c_name);
    else
        return dwarfTypeDescription_impl(type, cu, c_name);
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd)
{
    Logger::println("D to dwarf local variable");
    LOG_SCOPE;

    // get compile units
    llvm::DICompileUnit thisCU = DtoDwarfCompileUnit(gIR->dmodule);
    llvm::DICompileUnit varCU = DtoDwarfCompileUnit(getDefinedModule(vd));

    // get type description
    llvm::DIType TD = dwarfTypeDescription(vd->type, thisCU, NULL);
    if (TD.isNull())
        return; // unsupported

    // get variable description
    llvm::DIVariable VD = dwarfVariable(vd, TD);

    // declare
    dwarfDeclare(ll, VD);
}

//////////////////////////////////////////////////////////////////////////////////////////////////

llvm::DICompileUnit DtoDwarfCompileUnit(Module* m)
{
    Logger::println("D to dwarf compile_unit");
    LOG_SCOPE;

    // we might be generating for an import
    if (!m->ir.irModule)
        m->ir.irModule = new IrModule(m, m->srcfile->toChars());
    else if (!m->ir.irModule->diCompileUnit.isNull())
    {
        assert (m->ir.irModule->diCompileUnit.getGV()->getParent() == gIR->module
            && "debug info compile unit belongs to incorrect llvm module!");
        return m->ir.irModule->diCompileUnit;
    }

    // prepare srcpath
    std::string srcpath(FileName::path(m->srcfile->name->toChars()));
    if (!FileName::absolute(srcpath.c_str())) {
        llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory();
        tmp.appendComponent(srcpath);
        srcpath = tmp.toString();
        if (!srcpath.empty() && *srcpath.rbegin() != '/' && *srcpath.rbegin() != '\\')
            srcpath = srcpath + '/';
    }

    // make compile unit
    m->ir.irModule->diCompileUnit = gIR->difactory.CreateCompileUnit(
        global.params.symdebug == 2 ? DW_LANG_C : DW_LANG_D,
        m->srcfile->name->toChars(),
        srcpath,
        "LDC (http://www.dsource.org/projects/ldc)",
//FIXME: What do these two mean?
        false, // isMain,
        false // isOptimized
    );

    return m->ir.irModule->diCompileUnit;
}

//////////////////////////////////////////////////////////////////////////////////////////////////

llvm::DISubprogram DtoDwarfSubProgram(FuncDeclaration* fd)
{
    Logger::println("D to dwarf subprogram");
    LOG_SCOPE;

    llvm::DICompileUnit context = DtoDwarfCompileUnit(gIR->dmodule);
    llvm::DICompileUnit definition = DtoDwarfCompileUnit(getDefinedModule(fd));

    // FIXME: duplicates ?
    return gIR->difactory.CreateSubprogram(
        context, // context
        fd->toPrettyChars(), // name
        fd->toPrettyChars(), // display name
        fd->mangle(), // linkage name
        definition, // compile unit
        fd->loc.linnum, // line no
//FIXME: what's this type for?
        llvm::DIType(NULL), // type
        fd->protection == PROTprivate, // is local to unit
        context.getGV() == definition.getGV() // isdefinition
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

llvm::DISubprogram DtoDwarfSubProgramInternal(const char* prettyname, const char* mangledname)
{
    Logger::println("D to dwarf subprogram");
    LOG_SCOPE;

    llvm::DICompileUnit context = DtoDwarfCompileUnit(gIR->dmodule);

    // FIXME: duplicates ?
    return gIR->difactory.CreateSubprogram(
        context, // context
        prettyname, // name
        prettyname, // display name
        mangledname, // linkage name
        context, // compile unit
        0, // line no
//FIXME: what's this type for?
        llvm::DIType(NULL), // type
        true, // is local to unit
        true // isdefinition
    );
}

//////////////////////////////////////////////////////////////////////////////////////////////////

llvm::DIGlobalVariable DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd)
{
    Logger::println("D to dwarf global_variable");
    LOG_SCOPE;

    // FIXME: duplicates ?
    return dwarfGlobalVariable(ll, vd);
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void DtoDwarfFuncStart(FuncDeclaration* fd)
{
    Logger::println("D to dwarf funcstart");
    LOG_SCOPE;

    assert(!fd->ir.irFunc->diSubprogram.isNull());
    gIR->difactory.InsertSubprogramStart(fd->ir.irFunc->diSubprogram, gIR->scopebb());
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void DtoDwarfFuncEnd(FuncDeclaration* fd)
{
    Logger::println("D to dwarf funcend");
    LOG_SCOPE;

    assert(!fd->ir.irFunc->diSubprogram.isNull());
    gIR->difactory.InsertRegionEnd(fd->ir.irFunc->diSubprogram, gIR->scopebb());
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void DtoDwarfStopPoint(unsigned ln)
{
    Logger::println("D to dwarf stoppoint at line %u", ln);
    LOG_SCOPE;

    gIR->difactory.InsertStopPoint(
        DtoDwarfCompileUnit(getDefinedModule(gIR->func()->decl)), // compile unit
        ln, // line no
        0, // col no
        gIR->scopebb()
    );
}