view gen/typinf.cpp @ 155:7f92f477ff53 trunk

[svn r171] starting to move IR data from AST nodes into IRState; started with IrFunction
author ChristianK
date Tue, 29 Apr 2008 21:33:50 +0200
parents ce7b81fb957f
children ccd07d9f2ce9
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.

// Modifications for LLVMDC:
// Copyright (c) 2007 by Tomas Lindquist Olsen
// tomas at famolsen dk

#include <cstdio>
#include <cassert>

#include "gen/llvm.h"

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

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

#include "ir/irvar.h"

/*******************************************
 * Get a canonicalized form of the TypeInfo for use with the internal
 * runtime library routines. Canonicalized in that static arrays are
 * represented as dynamic arrays, enums are represented by their
 * underlying type, etc. This reduces the number of TypeInfo's needed,
 * so we can use the custom internal ones more.
 */

Expression *Type::getInternalTypeInfo(Scope *sc)
{   TypeInfoDeclaration *tid;
    Expression *e;
    Type *t;
    static TypeInfoDeclaration *internalTI[TMAX];

    //printf("Type::getInternalTypeInfo() %s\n", toChars());
    t = toBasetype();
    switch (t->ty)
    {
    case Tsarray:
        t = t->next->arrayOf(); // convert to corresponding dynamic array type
        break;

    case Tclass:
        if (((TypeClass *)t)->sym->isInterfaceDeclaration())
        break;
        goto Linternal;

    case Tarray:
        if (t->next->ty != Tclass)
        break;
        goto Linternal;

    case Tfunction:
    case Tdelegate:
    case Tpointer:
    Linternal:
        tid = internalTI[t->ty];
        if (!tid)
        {   tid = new TypeInfoDeclaration(t, 1);
        internalTI[t->ty] = tid;
        }
        e = new VarExp(0, tid);
        //e = e->addressOf(sc);
        e->type = tid->type;    // do this so we don't get redundant dereference
        return e;

    default:
        break;
    }
    //printf("\tcalling getTypeInfo() %s\n", t->toChars());
    return t->getTypeInfo(sc);
}


/****************************************************
 * Get the exact TypeInfo.
 */

Expression *Type::getTypeInfo(Scope *sc)
{
    Expression *e;
    Type *t;

    //printf("Type::getTypeInfo() %p, %s\n", this, toChars());
    t = merge();    // do this since not all Type's are merge'd
    if (!t->vtinfo)
    {   t->vtinfo = t->getTypeInfoDeclaration();
    assert(t->vtinfo);

    /* If this has a custom implementation in std/typeinfo, then
     * do not generate a COMDAT for it.
     */
    if (!t->builtinTypeInfo())
    {   // Generate COMDAT
        if (sc)         // if in semantic() pass
        {   // Find module that will go all the way to an object file
        Module *m = sc->module->importedFrom;
        m->members->push(t->vtinfo);
        }
        else            // if in obj generation pass
        {
        t->vtinfo->toObjFile();
        }
    }
    }
    e = new VarExp(0, t->vtinfo);
    //e = e->addressOf(sc);
    e->type = t->vtinfo->type;      // do this so we don't get redundant dereference
    return e;
}

enum RET TypeFunction::retStyle()
{
    return RETstack;
}

TypeInfoDeclaration *Type::getTypeInfoDeclaration()
{
    //printf("Type::getTypeInfoDeclaration() %s\n", toChars());
    return new TypeInfoDeclaration(this, 0);
}

TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration()
{
    return new TypeInfoTypedefDeclaration(this);
}

TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration()
{
    return new TypeInfoPointerDeclaration(this);
}

TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration()
{
    return new TypeInfoArrayDeclaration(this);
}

TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration()
{
    return new TypeInfoStaticArrayDeclaration(this);
}

TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration()
{
    return new TypeInfoAssociativeArrayDeclaration(this);
}

TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration()
{
    return new TypeInfoStructDeclaration(this);
}

TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration()
{
    if (sym->isInterfaceDeclaration())
    return new TypeInfoInterfaceDeclaration(this);
    else
    return new TypeInfoClassDeclaration(this);
}

TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration()
{
    return new TypeInfoEnumDeclaration(this);
}

TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration()
{
    return new TypeInfoFunctionDeclaration(this);
}

TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration()
{
    return new TypeInfoDelegateDeclaration(this);
}

TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration()
{
    return new TypeInfoTupleDeclaration(this);
}


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

/* These decide if there's an instance for them already in std.typeinfo,
 * because then the compiler doesn't need to build one.
 */

int Type::builtinTypeInfo()
{
    return 0;
}

int TypeBasic::builtinTypeInfo()
{
    return 1;
}

int TypeDArray::builtinTypeInfo()
{
    return next->isTypeBasic() != NULL;
}

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

/***************************************
 * Create a static array of TypeInfo references
 * corresponding to an array of Expression's.
 * Used to supply hidden _arguments[] value for variadic D functions.
 */

Expression *createTypeInfoArray(Scope *sc, Expression *exps[], int dim)
{
    assert(0);
    return NULL;
}

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

//////////////////////////////////////////////////////////////////////////////
//                             MAGIC   PLACE
//////////////////////////////////////////////////////////////////////////////

void TypeInfoDeclaration::toObjFile()
{
    gIR->resolveList.push_back(this);
}

void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
{
    if (tid->llvmResolved) return;
    tid->llvmResolved = true;

    Logger::println("DtoResolveTypeInfo(%s)", tid->toChars());
    LOG_SCOPE;

    tid->irGlobal = new IrGlobal(tid);

    gIR->declareList.push_back(tid);
}

void DtoDeclareTypeInfo(TypeInfoDeclaration* tid)
{
    if (tid->llvmDeclared) return;
    tid->llvmDeclared = true;

    Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars());
    LOG_SCOPE;

    std::string mangled(tid->mangle());

    Logger::println("type = '%s'", tid->tinfo->toChars());
    Logger::println("typeinfo mangle: %s", mangled.c_str());

    // this is a declaration of a builtin __initZ var
    if (tid->tinfo->builtinTypeInfo()) {
        llvm::Value* found = gIR->module->getNamedGlobal(mangled);
        if (!found)
        {
            const llvm::Type* t = llvm::OpaqueType::get();
            llvm::GlobalVariable* g = new llvm::GlobalVariable(t, true, llvm::GlobalValue::ExternalLinkage, NULL, mangled, gIR->module);
            assert(g);
            /*if (!tid->irGlobal)
                tid->irGlobal = new IrGlobal(tid);*/
            tid->irGlobal->value = g;
            mangled.append("__TYPE");
            gIR->module->addTypeName(mangled, tid->irGlobal->value->getType()->getContainedType(0));
            Logger::println("Got typeinfo var: %s", tid->irGlobal->value->getName().c_str());
            tid->llvmInitialized = true;
            tid->llvmDefined = true;
        }
        else if (!tid->irGlobal->value) {
            tid->irGlobal->value = found;
            tid->llvmInitialized = true;
            tid->llvmDefined = true;
        }
    }
    // custom typedef
    else {
        tid->llvmDeclare();
        gIR->constInitList.push_back(tid);
    }
}

void DtoConstInitTypeInfo(TypeInfoDeclaration* tid)
{
    if (tid->llvmInitialized) return;
    tid->llvmInitialized = true;

    Logger::println("DtoConstInitTypeInfo(%s)", tid->toChars());
    LOG_SCOPE;

    gIR->defineList.push_back(tid);
}

void DtoDefineTypeInfo(TypeInfoDeclaration* tid)
{
    if (tid->llvmDefined) return;
    tid->llvmDefined = true;

    Logger::println("DtoDefineTypeInfo(%s)", tid->toChars());
    LOG_SCOPE;

    tid->llvmDefine();
}

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

void TypeInfoDeclaration::toDt(dt_t **pdt)
{
    assert(0 && "TypeInfoDeclaration::toDt");
}

void TypeInfoDeclaration::llvmDeclare()
{
    assert(0 && "TypeInfoDeclaration::llvmDeclare");
}

void TypeInfoDeclaration::llvmDefine()
{
    assert(0 && "TypeInfoDeclaration::llvmDeclare");
}

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

void TypeInfoTypedefDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoTypedefDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    ClassDeclaration* base = Type::typeinfotypedef;
    DtoResolveClass(base);

    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoTypedefDeclaration::llvmDefine()
{
    Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    ClassDeclaration* base = Type::typeinfotypedef;
    DtoForceConstInitDsymbol(base);

    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
    Logger::cout() << "got stype: " << *stype << '\n';

    // vtbl
    std::vector<llvm::Constant*> sinits;
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(getNullPtr(getPtrToType(llvm::Type::Int8Ty)));

    assert(tinfo->ty == Ttypedef);
    TypeTypedef *tc = (TypeTypedef *)tinfo;
    TypedefDeclaration *sd = tc->sym;

    // TypeInfo base
    //const llvm::PointerType* basept = isaPointer(initZ->getOperand(1)->getType());
    //sinits.push_back(llvm::ConstantPointerNull::get(basept));
    Logger::println("generating base typeinfo");
    //sd->basetype = sd->basetype->merge();

    sd->basetype->getTypeInfo(NULL);        // generate vtinfo
    assert(sd->basetype->vtinfo);
    DtoForceDeclareDsymbol(sd->basetype->vtinfo);

    assert(sd->basetype->vtinfo->irGlobal->value);
    assert(llvm::isa<llvm::Constant>(sd->basetype->vtinfo->irGlobal->value));
    llvm::Constant* castbase = llvm::cast<llvm::Constant>(sd->basetype->vtinfo->irGlobal->value);
    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(2));
    sinits.push_back(castbase);

    // char[] name
    char *name = sd->toPrettyChars();
    sinits.push_back(DtoConstString(name));
    assert(sinits.back()->getType() == stype->getElementType(3));

    // void[] init
    const llvm::PointerType* initpt = getPtrToType(llvm::Type::Int8Ty);
    if (tinfo->isZeroInit() || !sd->init) // 0 initializer, or the same as the base type
    {
        sinits.push_back(DtoConstSlice(DtoConstSize_t(0), getNullPtr(initpt)));
    }
    else
    {
        llvm::Constant* ci = DtoConstInitializer(sd->basetype, sd->init);
        std::string ciname(sd->mangle());
        ciname.append("__init");
        llvm::GlobalVariable* civar = new llvm::GlobalVariable(DtoType(sd->basetype),true,llvm::GlobalValue::InternalLinkage,ci,ciname,gIR->module);
        llvm::Constant* cicast = llvm::ConstantExpr::getBitCast(civar, initpt);
        size_t cisize = getTypeStoreSize(DtoType(sd->basetype));
        sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast));
    }

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoTypedefDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoEnumDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoEnumDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    ClassDeclaration* base = Type::typeinfoenum;
    DtoResolveClass(base);

    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoEnumDeclaration::llvmDefine()
{
    Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    ClassDeclaration* base = Type::typeinfoenum;
    DtoForceConstInitDsymbol(base);

    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // vtbl
    std::vector<llvm::Constant*> sinits;
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    assert(tinfo->ty == Tenum);
    TypeEnum *tc = (TypeEnum *)tinfo;
    EnumDeclaration *sd = tc->sym;

    // TypeInfo base
    //const llvm::PointerType* basept = isaPointer(initZ->getOperand(1)->getType());
    //sinits.push_back(llvm::ConstantPointerNull::get(basept));
    Logger::println("generating base typeinfo");
    //sd->basetype = sd->basetype->merge();

    sd->memtype->getTypeInfo(NULL);        // generate vtinfo
    assert(sd->memtype->vtinfo);
    DtoForceDeclareDsymbol(sd->memtype->vtinfo);

    assert(llvm::isa<llvm::Constant>(sd->memtype->vtinfo->irGlobal->value));
    llvm::Constant* castbase = llvm::cast<llvm::Constant>(sd->memtype->vtinfo->irGlobal->value);
    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(2));
    sinits.push_back(castbase);

    // char[] name
    char *name = sd->toPrettyChars();
    sinits.push_back(DtoConstString(name));
    assert(sinits.back()->getType() == stype->getElementType(3));

    // void[] init
    const llvm::PointerType* initpt = getPtrToType(llvm::Type::Int8Ty);
    if (tinfo->isZeroInit() || !sd->defaultval) // 0 initializer, or the same as the base type
    {
        sinits.push_back(DtoConstSlice(DtoConstSize_t(0), llvm::ConstantPointerNull::get(initpt)));
    }
    else
    {
        const llvm::Type* memty = DtoType(sd->memtype);
        llvm::Constant* ci = llvm::ConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned());
        std::string ciname(sd->mangle());
        ciname.append("__init");
        llvm::GlobalVariable* civar = new llvm::GlobalVariable(memty,true,llvm::GlobalValue::InternalLinkage,ci,ciname,gIR->module);
        llvm::Constant* cicast = llvm::ConstantExpr::getBitCast(civar, initpt);
        size_t cisize = getTypeStoreSize(memty);
        sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast));
    }

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoEnumDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

static llvm::Constant* LLVM_D_Declare_TypeInfoBase(TypeInfoDeclaration* tid, ClassDeclaration* cd)
{
    ClassDeclaration* base = cd;
    DtoResolveClass(base);

    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    tid->irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,tid->toChars(),gIR->module);
}

static llvm::Constant* LLVM_D_Define_TypeInfoBase(Type* basetype, TypeInfoDeclaration* tid, ClassDeclaration* cd)
{
    ClassDeclaration* base = cd;
    DtoForceConstInitDsymbol(base);

    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // vtbl
    std::vector<llvm::Constant*> sinits;
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // TypeInfo base
    Logger::println("generating base typeinfo");
    basetype->getTypeInfo(NULL);
    assert(basetype->vtinfo);
    DtoForceDeclareDsymbol(basetype->vtinfo);
    assert(llvm::isa<llvm::Constant>(basetype->vtinfo->irGlobal->value));
    llvm::Constant* castbase = llvm::cast<llvm::Constant>(basetype->vtinfo->irGlobal->value);
    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(2));
    sinits.push_back(castbase);

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(tid->irGlobal->value)->setInitializer(tiInit);
}

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

void TypeInfoPointerDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoPointerDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tpointer);
    TypePointer *tc = (TypePointer *)tinfo;

    LLVM_D_Declare_TypeInfoBase(this, Type::typeinfopointer);
}

void TypeInfoPointerDeclaration::llvmDefine()
{
    Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tpointer);
    TypePointer *tc = (TypePointer *)tinfo;

    LLVM_D_Define_TypeInfoBase(tc->next, this, Type::typeinfopointer);
}

void TypeInfoPointerDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoArrayDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoArrayDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tarray);
    TypeDArray *tc = (TypeDArray *)tinfo;

    LLVM_D_Declare_TypeInfoBase(this, Type::typeinfoarray);
}

void TypeInfoArrayDeclaration::llvmDefine()
{
    Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tarray);
    TypeDArray *tc = (TypeDArray *)tinfo;

    LLVM_D_Define_TypeInfoBase(tc->next, this, Type::typeinfoarray);
}

void TypeInfoArrayDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoStaticArrayDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoStaticArrayDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfostaticarray;
    DtoResolveClass(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoStaticArrayDeclaration::llvmDefine()
{
    Logger::println("TypeInfoStaticArrayDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfostaticarray;
    DtoForceConstInitDsymbol(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // initializer vector
    std::vector<llvm::Constant*> sinits;
    // first is always the vtable
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // value typeinfo
    assert(tinfo->ty == Tsarray);
    TypeSArray *tc = (TypeSArray *)tinfo;
    tc->next->getTypeInfo(NULL);

    // get symbol
    assert(tc->next->vtinfo);
    DtoForceDeclareDsymbol(tc->next->vtinfo);
    llvm::Constant* castbase = isaConstant(tc->next->vtinfo->irGlobal->value);
    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(2));
    sinits.push_back(castbase);

    // length
    sinits.push_back(DtoConstSize_t(tc->dim->toInteger()));

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoStaticArrayDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoAssociativeArrayDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoAssociativeArrayDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfoassociativearray;
    DtoResolveClass(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoAssociativeArrayDeclaration::llvmDefine()
{
    Logger::println("TypeInfoAssociativeArrayDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfoassociativearray;
    DtoForceConstInitDsymbol(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // initializer vector
    std::vector<llvm::Constant*> sinits;
    // first is always the vtable
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // get type
    assert(tinfo->ty == Taarray);
    TypeAArray *tc = (TypeAArray *)tinfo;

    // value typeinfo
    tc->next->getTypeInfo(NULL);

    // get symbol
    assert(tc->next->vtinfo);
    DtoForceDeclareDsymbol(tc->next->vtinfo);
    llvm::Constant* castbase = isaConstant(tc->next->vtinfo->irGlobal->value);
    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(2));
    sinits.push_back(castbase);

    // key typeinfo
    tc->index->getTypeInfo(NULL);

    // get symbol
    assert(tc->index->vtinfo);
    DtoForceDeclareDsymbol(tc->index->vtinfo);
    castbase = isaConstant(tc->index->vtinfo->irGlobal->value);
    castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(3));
    sinits.push_back(castbase);

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoAssociativeArrayDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoFunctionDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoFunctionDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tfunction);
    TypeFunction *tc = (TypeFunction *)tinfo;

    LLVM_D_Declare_TypeInfoBase(this, Type::typeinfofunction);
}

void TypeInfoFunctionDeclaration::llvmDefine()
{
    Logger::println("TypeInfoFunctionDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tfunction);
    TypeFunction *tc = (TypeFunction *)tinfo;

    LLVM_D_Define_TypeInfoBase(tc->next, this, Type::typeinfofunction);
}

void TypeInfoFunctionDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoDelegateDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoDelegateDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tdelegate);
    TypeDelegate *tc = (TypeDelegate *)tinfo;

    LLVM_D_Declare_TypeInfoBase(this, Type::typeinfodelegate);
}

void TypeInfoDelegateDeclaration::llvmDefine()
{
    Logger::println("TypeInfoDelegateDeclaration::toDt() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tdelegate);
    TypeDelegate *tc = (TypeDelegate *)tinfo;

    LLVM_D_Define_TypeInfoBase(tc->next->next, this, Type::typeinfodelegate);
}

void TypeInfoDelegateDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoStructDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoStructDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tstruct);
    TypeStruct *tc = (TypeStruct *)tinfo;
    StructDeclaration *sd = tc->sym;
    DtoResolveDsymbol(sd);

    ClassDeclaration* base = Type::typeinfostruct;
    DtoResolveClass(base);

    const llvm::StructType* stype = isaStruct(((TypeClass*)base->type)->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoStructDeclaration::llvmDefine()
{
    Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    assert(tinfo->ty == Tstruct);
    TypeStruct *tc = (TypeStruct *)tinfo;
    StructDeclaration *sd = tc->sym;
    DtoForceConstInitDsymbol(sd);

    ClassDeclaration* base = Type::typeinfostruct;
    DtoForceConstInitDsymbol(base);

    const llvm::StructType* stype = isaStruct(((TypeClass*)base->type)->llvmType->get());

    // vtbl
    std::vector<llvm::Constant*> sinits;
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // char[] name
    char *name = sd->toPrettyChars();
    sinits.push_back(DtoConstString(name));
    //Logger::println("************** A");
    assert(sinits.back()->getType() == stype->getElementType(2));

    // void[] init
    const llvm::PointerType* initpt = getPtrToType(llvm::Type::Int8Ty);
    if (sd->zeroInit) // 0 initializer, or the same as the base type
    {
        sinits.push_back(DtoConstSlice(DtoConstSize_t(0), llvm::ConstantPointerNull::get(initpt)));
    }
    else
    {
        size_t cisize = getTypeStoreSize(tc->llvmType->get());
        llvm::Constant* cicast = llvm::ConstantExpr::getBitCast(sd->irStruct->init, initpt);
        sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast));
    }

    // toX functions ground work
    FuncDeclaration *fd;
    FuncDeclaration *fdx;
    TypeFunction *tf;
    Type *ta;
    Dsymbol *s;

    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
    Scope sc;

    tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
    tftohash = (TypeFunction *)tftohash->semantic(0, &sc);

    tftostring = new TypeFunction(NULL, Type::tchar->arrayOf(), 0, LINKd);
    tftostring = (TypeFunction *)tftostring->semantic(0, &sc);
    }

    TypeFunction *tfeqptr;
    {
    Scope sc;
    Arguments *arguments = new Arguments;
    Argument *arg = new Argument(STCin, tc->pointerTo(), NULL, NULL);

    arguments->push(arg);
    tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
    tfeqptr = (TypeFunction *)tfeqptr->semantic(0, &sc);
    }

#if 0
    TypeFunction *tfeq;
    {
    Scope sc;
    Array *arguments = new Array;
    Argument *arg = new Argument(In, tc, NULL, NULL);

    arguments->push(arg);
    tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
    tfeq = (TypeFunction *)tfeq->semantic(0, &sc);
    }
#endif

    //Logger::println("************** B");
    const llvm::PointerType* ptty = isaPointer(stype->getElementType(4));
    assert(ptty);

    s = search_function(sd, Id::tohash);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {
        fd = fdx->overloadExactMatch(tftohash);
        if (fd) {
            DtoForceDeclareDsymbol(fd);
            assert(gIR->irFunc[fd]->func != 0);
            llvm::Constant* c = isaConstant(gIR->irFunc[fd]->func);
            assert(c);
            c = llvm::ConstantExpr::getBitCast(c, ptty);
            sinits.push_back(c);
        }
        else {
            //fdx->error("must be declared as extern (D) uint toHash()");
            sinits.push_back(llvm::ConstantPointerNull::get(ptty));
        }
    }
    else {
        sinits.push_back(llvm::ConstantPointerNull::get(ptty));
    }

    s = search_function(sd, Id::eq);
    fdx = s ? s->isFuncDeclaration() : NULL;
    for (int i = 0; i < 2; i++)
    {
        //Logger::println("************** C %d", i);
        ptty = isaPointer(stype->getElementType(5+i));
        if (fdx)
        {
            fd = fdx->overloadExactMatch(tfeqptr);
            if (fd) {
                DtoForceDeclareDsymbol(fd);
                assert(gIR->irFunc[fd]->func != 0);
                llvm::Constant* c = isaConstant(gIR->irFunc[fd]->func);
                assert(c);
                c = llvm::ConstantExpr::getBitCast(c, ptty);
                sinits.push_back(c);
            }
            else {
                //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars());
                sinits.push_back(llvm::ConstantPointerNull::get(ptty));
            }
        }
        else {
            sinits.push_back(llvm::ConstantPointerNull::get(ptty));
        }

        s = search_function(sd, Id::cmp);
        fdx = s ? s->isFuncDeclaration() : NULL;
    }

    //Logger::println("************** D");
    ptty = isaPointer(stype->getElementType(7));
    s = search_function(sd, Id::tostring);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {
        fd = fdx->overloadExactMatch(tftostring);
        if (fd) {
            DtoForceDeclareDsymbol(fd);
            assert(gIR->irFunc[fd]->func != 0);
            llvm::Constant* c = isaConstant(gIR->irFunc[fd]->func);
            assert(c);
            c = llvm::ConstantExpr::getBitCast(c, ptty);
            sinits.push_back(c);
        }
        else {
            //fdx->error("must be declared as extern (D) char[] toString()");
            sinits.push_back(llvm::ConstantPointerNull::get(ptty));
        }
    }
    else {
        sinits.push_back(llvm::ConstantPointerNull::get(ptty));
    }

    // uint m_flags;
    sinits.push_back(DtoConstUint(tc->hasPointers()));

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,tiInit,toChars(),gIR->module);

    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoStructDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoClassDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoClassDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfoclass;
    assert(base);
    DtoResolveClass(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoClassDeclaration::llvmDefine()
{
    Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfoclass;
    assert(base);
    DtoForceConstInitDsymbol(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // initializer vector
    std::vector<llvm::Constant*> sinits;
    // first is always the vtable
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // get classinfo
    assert(tinfo->ty == Tclass);
    TypeClass *tc = (TypeClass *)tinfo;
    assert(tc->sym->irStruct->classInfo);
    sinits.push_back(tc->sym->irStruct->classInfo);

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoClassDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoInterfaceDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoInterfaceDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfointerface;
    assert(base);
    DtoResolveClass(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoInterfaceDeclaration::llvmDefine()
{
    Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfointerface;
    assert(base);
    DtoForceConstInitDsymbol(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // initializer vector
    std::vector<llvm::Constant*> sinits;
    // first is always the vtable
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // get classinfo
    assert(tinfo->ty == Tclass);
    TypeClass *tc = (TypeClass *)tinfo;
    assert(tc->sym->irStruct->classInfo);
    sinits.push_back(tc->sym->irStruct->classInfo);

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoInterfaceDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}

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

void TypeInfoTupleDeclaration::llvmDeclare()
{
    Logger::println("TypeInfoTupleDeclaration::llvmDeclare() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfotypelist;
    assert(base);
    DtoResolveClass(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // create the symbol
    irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
}

void TypeInfoTupleDeclaration::llvmDefine()
{
    Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    // init typeinfo class
    ClassDeclaration* base = Type::typeinfotypelist;
    assert(base);
    DtoForceConstInitDsymbol(base);

    // get type of typeinfo class
    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());

    // initializer vector
    std::vector<llvm::Constant*> sinits;
    // first is always the vtable
    sinits.push_back(base->irStruct->vtbl);

    // monitor
    sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));

    // create elements array
    assert(tinfo->ty == Ttuple);
    TypeTuple *tu = (TypeTuple *)tinfo;

    size_t dim = tu->arguments->dim;
    std::vector<llvm::Constant*> arrInits;

    const llvm::Type* tiTy = Type::typeinfo->type->llvmType->get();
    tiTy = getPtrToType(tiTy);

    for (size_t i = 0; i < dim; i++)
    {
        Argument *arg = (Argument *)tu->arguments->data[i];
        arg->type->getTypeInfo(NULL);
        DtoForceDeclareDsymbol(arg->type->vtinfo);
        assert(arg->type->vtinfo->irGlobal->value);
        llvm::Constant* c = isaConstant(arg->type->vtinfo->irGlobal->value);
        c = llvm::ConstantExpr::getBitCast(c, tiTy);
        arrInits.push_back(c);
    }

    // build array type
    const llvm::ArrayType* arrTy = llvm::ArrayType::get(tiTy, dim);
    llvm::Constant* arrC = llvm::ConstantArray::get(arrTy, arrInits);

    // build the slice
    llvm::Constant* slice = DtoConstSlice(DtoConstSize_t(dim), arrC);
    sinits.push_back(slice);

    // create the symbol
    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
    isaGlobalVar(irGlobal->value)->setInitializer(tiInit);
}

void TypeInfoTupleDeclaration::toDt(dt_t **pdt)
{
    assert(0);
}