view gen/toobj.cpp @ 100:5071469303d4 trunk

[svn r104] TONS OF FIXES. Split up declaration, constant initializer gen and definition for globals, structs, classes and functions. Improved ClassInfo support (not complete), not in vtable yet. Fixed a bunch of forward reference problems. Much more. Major commit! :)
author lindquist
date Fri, 16 Nov 2007 08:21:47 +0100
parents 6789050b5ad1
children 027b8d8b71ec
line wrap: on
line source


// Copyright (c) 1999-2004 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.

#include <cstddef>
#include <iostream>
#include <fstream>

#include "gen/llvm.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineRegistry.h"

#include "mars.h"
#include "module.h"
#include "mtype.h"
#include "declaration.h"
#include "statement.h"
#include "enum.h"
#include "aggregate.h"
#include "init.h"
#include "attrib.h"
#include "id.h"
#include "import.h"
#include "template.h"
#include "scope.h"

#include "gen/irstate.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "gen/arrays.h"
#include "gen/structs.h"
#include "gen/classes.h"
#include "gen/functions.h"
#include "gen/todebug.h"
#include "gen/runtime.h"

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

void
Module::genobjfile()
{
    Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n';
    LOG_SCOPE;

    // start by deleting the old object file
    deleteObjFile();

    // create a new ir state
    IRState ir;
    gIR = &ir;
    ir.dmodule = this;

    // name the module
    std::string mname(toChars());
    if (md != 0)
        mname = md->toChars();
    ir.module = new llvm::Module(mname);

    // set target stuff
    std::string target_triple(global.params.tt_arch);
    target_triple.append(global.params.tt_os);
    ir.module->setTargetTriple(target_triple);
    ir.module->setDataLayout(global.params.data_layout);

    // heavily inspired by tools/llc/llc.cpp:200-230
    const llvm::TargetMachineRegistry::Entry* targetEntry;
    std::string targetError;
    targetEntry = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(*ir.module, targetError);
    assert(targetEntry && "Failed to find a static target for module");
    std::auto_ptr<llvm::TargetMachine> targetPtr(targetEntry->CtorFn(*ir.module, "")); // TODO: replace "" with features
    assert(targetPtr.get() && "Could not allocate target machine!");
    llvm::TargetMachine &targetMachine = *targetPtr.get();
    gTargetData = targetMachine.getTargetData();

    // debug info
    if (global.params.symdebug) {
        RegisterDwarfSymbols(ir.module);
        ir.dmodule->llvmCompileUnit = DtoDwarfCompileUnit(this,true);
    }

    // process module members
    for (int k=0; k < members->dim; k++) {
        Dsymbol* dsym = (Dsymbol*)(members->data[k]);
        assert(dsym);
        dsym->toObjFile();
    }

    // process deferred const initializers
    for (size_t i=0; i<ir.constInitQueue.size(); ++i) {
        DtoConstInitDsymbol(ir.constInitQueue[i]);
    }

    // process deferred definitions
    for (size_t i=0; i<ir.defineQueue.size(); ++i) {
        DtoDefineDsymbol(ir.defineQueue[i]);
    }

    // generate ModuleInfo
    genmoduleinfo();

    gTargetData = 0;

    // emit the llvm main function if necessary
    if (ir.emitMain) {
        DtoMain();
    }

    // verify the llvm
    if (!global.params.novalidate) {
        std::string verifyErr;
        Logger::println("Verifying module...");
        if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr))
        {
            error("%s", verifyErr.c_str());
            fatal();
        }
        else {
            Logger::println("Verification passed!");
        }
    }

    // run passes
    // TODO

    // write bytecode
    {
        Logger::println("Writing LLVM bitcode\n");
        std::ofstream bos(bcfile->name->toChars(), std::ios::binary);
        llvm::WriteBitcodeToFile(ir.module, bos);
    }

    // disassemble ?
    if (global.params.disassemble) {
        Logger::println("Writing LLVM asm to: %s\n", llfile->name->toChars());
        std::ofstream aos(llfile->name->toChars());
        ir.module->print(aos);
    }

    delete ir.module;
    gIR = NULL;
}

/* ================================================================== */

// Put out instance of ModuleInfo for this Module

void Module::genmoduleinfo()
{
//      The layout is:
//        {
//         void **vptr;
//         monitor_t monitor;
//         char[] name;        // class name
//         ModuleInfo importedModules[];
//         ClassInfo localClasses[];
//         uint flags;         // initialization state
//         void *ctor;
//         void *dtor;
//         void *unitTest;
//        }

    if (moduleinfo) {
        Logger::println("moduleinfo");
    }
    if (vmoduleinfo) {
        Logger::println("vmoduleinfo");
    }
    if (needModuleInfo()) {
        Logger::attention("module info is needed but skipped");
    }


    /*
    Symbol *msym = toSymbol();
    unsigned offset;
    unsigned sizeof_ModuleInfo = 12 * PTRSIZE;

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

    csym->Sclass = SCglobal;
    csym->Sfl = FLdata;

//      The layout is:
//        {
//         void **vptr;
//         monitor_t monitor;
//         char[] name;        // class name
//         ModuleInfo importedModules[];
//         ClassInfo localClasses[];
//         uint flags;         // initialization state
//         void *ctor;
//         void *dtor;
//         void *unitTest;
//        }
    dt_t *dt = NULL;

    if (moduleinfo)
    dtxoff(&dt, moduleinfo->toVtblSymbol(), 0, TYnptr); // vtbl for ModuleInfo
    else
    dtdword(&dt, 0);        // BUG: should be an assert()
    dtdword(&dt, 0);            // monitor

    // name[]
    char *name = toPrettyChars();
    size_t namelen = strlen(name);
    dtdword(&dt, namelen);
    dtabytes(&dt, TYnptr, 0, namelen + 1, name);

    ClassDeclarations aclasses;
    int i;

    //printf("members->dim = %d\n", members->dim);
    for (i = 0; i < members->dim; i++)
    {
    Dsymbol *member;

    member = (Dsymbol *)members->data[i];
    //printf("\tmember '%s'\n", member->toChars());
    member->addLocalClass(&aclasses);
    }

    // importedModules[]
    int aimports_dim = aimports.dim;
    for (i = 0; i < aimports.dim; i++)
    {   Module *m = (Module *)aimports.data[i];
    if (!m->needModuleInfo())
        aimports_dim--;
    }
    dtdword(&dt, aimports_dim);
    if (aimports.dim)
    dtxoff(&dt, csym, sizeof_ModuleInfo, TYnptr);
    else
    dtdword(&dt, 0);

    // localClasses[]
    dtdword(&dt, aclasses.dim);
    if (aclasses.dim)
    dtxoff(&dt, csym, sizeof_ModuleInfo + aimports_dim * PTRSIZE, TYnptr);
    else
    dtdword(&dt, 0);

    if (needmoduleinfo)
    dtdword(&dt, 0);        // flags (4 means MIstandalone)
    else
    dtdword(&dt, 4);        // flags (4 means MIstandalone)

    if (sctor)
    dtxoff(&dt, sctor, 0, TYnptr);
    else
    dtdword(&dt, 0);

    if (sdtor)
    dtxoff(&dt, sdtor, 0, TYnptr);
    else
    dtdword(&dt, 0);

    if (stest)
    dtxoff(&dt, stest, 0, TYnptr);
    else
    dtdword(&dt, 0);

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

    for (i = 0; i < aimports.dim; i++)
    {
    Module *m;

    m = (Module *)aimports.data[i];
    if (m->needModuleInfo())
    {   Symbol *s = m->toSymbol();
        s->Sflags |= SFLweak;
        dtxoff(&dt, s, 0, TYnptr);
    }
    }

    for (i = 0; i < aclasses.dim; i++)
    {
    ClassDeclaration *cd;

    cd = (ClassDeclaration *)aclasses.data[i];
    dtxoff(&dt, cd->toSymbol(), 0, TYnptr);
    }

    csym->Sdt = dt;
#if ELFOBJ
    // Cannot be CONST because the startup code sets flag bits in it
    csym->Sseg = DATA;
#endif
    outdata(csym);

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

    obj_moduleinfo(msym);
    */
}

/* ================================================================== */

void Dsymbol::toObjFile()
{
    Logger::println("Ignoring Dsymbol::toObjFile for %s", toChars());
}

/* ================================================================== */

void Declaration::toObjFile()
{
    Logger::println("Ignoring Declaration::toObjFile for %s", toChars());
}

/* ================================================================== */

void InterfaceDeclaration::toObjFile()
{
    Logger::println("Ignoring InterfaceDeclaration::toObjFile for %s", toChars());
}

/* ================================================================== */

void StructDeclaration::toObjFile()
{
    DtoDeclareStruct(this);
}

/* ================================================================== */

static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx)
{
    // start at the bottom of the inheritance chain
    if (cd->baseClass != 0) {
        unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx);
        if (o != (unsigned)-1)
            return o;
    }

    // check this class
    unsigned i;
    for (i=0; i<cd->fields.dim; ++i) {
        VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i];
        if (os == vd->offset)
            return i+idx;
    }
    idx += i;

    return (unsigned)-1;
}

void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
{
    unsigned idx = 0;
    unsigned r = LLVM_ClassOffsetToIndex(this, os, idx);
    assert(r != (unsigned)-1 && "Offset not found in any aggregate field");
    result.push_back(r+1); // vtable is 0
}

/* ================================================================== */

void ClassDeclaration::toObjFile()
{
    DtoDeclareClass(this);
}

/******************************************
 * Get offset of base class's vtbl[] initializer from start of csym.
 * Returns ~0 if not this csym.
 */

unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc)
{
  return ~0;
}

/* ================================================================== */

void VarDeclaration::toObjFile()
{
    Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars());
    LOG_SCOPE;

    if (aliassym)
    {
        Logger::println("alias sym");
        toAlias()->toObjFile();
        return;
    }

    // global variable or magic
    if (isDataseg())
    {
        if (llvmTouched) return;
        else llvmTouched = true;

        llvmIRGlobal = new IRGlobal(this);

        Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());

        bool _isconst = isConst();
        if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer())
            _isconst = false;

        llvm::GlobalValue::LinkageTypes _linkage;
        bool istempl = false;
        bool static_local = false;
        if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) {
            _linkage = llvm::GlobalValue::WeakLinkage;
            istempl = true;
        }
        else if (parent && parent->isFuncDeclaration()) {
            _linkage = llvm::GlobalValue::InternalLinkage;
            static_local = true;
        }
        else
            _linkage = DtoLinkage(protection, storage_class);

        const llvm::Type* _type = llvmIRGlobal->type.get();

        Logger::println("Creating global variable");
        std::string _name(mangle());

        llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,NULL,_name,gIR->module);
        llvmValue = gvar;

        if (static_local)
            DtoConstInitGlobal(this);
        else
            gIR->constInitQueue.push_back(this);

        //if (storage_class & STCprivate)
        //    gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility);
    }

    // inside aggregate declaration. declare a field.
    else
    {
        Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset);

        const llvm::Type* _type = DtoType(type);

        // add the field in the IRStruct
        gIR->topstruct()->offsets.insert(std::make_pair(offset, IRStruct::Offset(this, _type)));
    }

    Logger::println("VarDeclaration::toObjFile is done");
}

/* ================================================================== */

void TypedefDeclaration::toObjFile()
{
    static int tdi = 0;
    Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars());
    LOG_SCOPE;

    // generate typeinfo
    type->getTypeInfo(NULL);
}

/* ================================================================== */

void EnumDeclaration::toObjFile()
{
    Logger::println("Ignoring EnumDeclaration::toObjFile for %s", toChars());
}

/* ================================================================== */

void FuncDeclaration::toObjFile()
{
    DtoDeclareFunction(this);
}