//===-- typinf.cpp --------------------------------------------------------===//
//
//                         LDC – the LLVM D compiler
//
// This file mostly consists of code under the BSD-style LDC license, but some
// parts have been derived from DMD as noted below. See the LICENSE file for
// details.
//
//===----------------------------------------------------------------------===//

// 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 LDC:
// 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/llvmhelpers.h"
#include "gen/arrays.h"
#include "gen/structs.h"
#include "gen/classes.h"
#include "gen/linkage.h"
#include "gen/metadata.h"
#include "gen/rttibuilder.h"

#include "ir/irvar.h"
#include "ir/irtype.h"
#include <ir/irtypeclass.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:
#if 0
        // convert to corresponding dynamic array type
        t = t->nextOf()->mutableOf()->arrayOf();
#endif
        break;

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

    case Tarray:
    #if DMDV2
        // convert to corresponding dynamic array type
        t = t->nextOf()->mutableOf()->arrayOf();
    #endif
        if (t->nextOf()->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)
{
    //printf("Type::getTypeInfo() %p, %s\n", this, toChars());
    if (!Type::typeinfo)
    {
        error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch");
        fatal();
    }

    Expression *e = 0;
    Type *t = merge2(); // do this since not all Type's are merge'd

    if (!t->vtinfo)
    {
#if DMDV2
        if (t->isShared())
            t->vtinfo = new TypeInfoSharedDeclaration(t);
        else if (t->isConst())
            t->vtinfo = new TypeInfoConstDeclaration(t);
        else if (t->isImmutable())
            t->vtinfo = new TypeInfoInvariantDeclaration(t);
        else if (t->isWild())
            t->vtinfo = new TypeInfoWildDeclaration(t);
        else
#endif
            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
            {
#if IN_DMD
                t->vtinfo->toObjFile(0); // TODO: multiobj
#else
                t->vtinfo->codegen(sir);
#endif
            }
        }
    }
    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);
}

#if DMDV2
TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration()
{
    return new TypeInfoVectorDeclaration(this);
}
#endif

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()
{
#if DMDV2
    return mod ? 0 : 1;
#else
    return 1;
#endif
}

int TypeDArray::builtinTypeInfo()
{
#if DMDV2
    return !mod && ((next->isTypeBasic() != NULL && !next->mod) ||
        // strings are so common, make them builtin
        (next->ty == Tchar && next->mod == MODimmutable));
#else
    return next->isTypeBasic() != NULL;
#endif
}

int TypeClass::builtinTypeInfo()
{
    /* This is statically put out with the ClassInfo, so
     * claim it is built in so it isn't regenerated by each module.
     */
#if IN_DMD
    return mod ? 0 : 1;
#elif IN_LLVM
    // FIXME if I enable this, the way LDC does typeinfo will cause a bunch
    // of linker errors to missing class typeinfo definitions.
    return 0;
#endif
}

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

//////////////////////////////////////////////////////////////////////////////
//                             MAGIC   PLACE
//                                (wut?)
//////////////////////////////////////////////////////////////////////////////

void DtoResolveTypeInfo(TypeInfoDeclaration* tid);
void DtoDeclareTypeInfo(TypeInfoDeclaration* tid);

void TypeInfoDeclaration::codegen(Ir*)
{
    DtoResolveTypeInfo(this);
}

void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
{
    if (tid->ir.resolved) return;
    tid->ir.resolved = true;

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

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

    IrGlobal* irg = new IrGlobal(tid);
    irg->value = gIR->module->getGlobalVariable(mangle);

    if (!irg->value) {
        if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var
            irg->type = Type::typeinfo->type->irtype->isClass()->getMemoryLLType();
        else
            irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars());
        irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true,
                                              TYPEINFO_LINKAGE_TYPE, NULL, mangle);
    } else {
        irg->type = irg->value->getType()->getContainedType(0);
    }

    tid->ir.irGlobal = irg;

#if USE_METADATA
    // don't do this for void or llvm will crash
    if (tid->tinfo->ty != Tvoid) {
        // Add some metadata for use by optimization passes.
        std::string metaname = std::string(TD_PREFIX) + mangle;
        llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname);
        // Don't generate metadata for non-concrete types
        // (such as tuple types, slice types, typeof(expr), etc.)
        if (!meta && tid->tinfo->toBasetype()->ty < Terror) {
            // Construct the fields
            MDNodeField* mdVals[TD_NumFields];
            if (TD_Confirm >= 0)
                mdVals[TD_Confirm] = llvm::cast<MDNodeField>(irg->value);
            mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo));
            // Construct the metadata and insert it into the module.
            llvm::NamedMDNode* node = gIR->module->getOrInsertNamedMetadata(metaname);
            node->addOperand(llvm::MDNode::get(gIR->context(),
                llvm::makeArrayRef(mdVals, TD_NumFields)));
        }
    }
#endif // USE_METADATA

    DtoDeclareTypeInfo(tid);
}

void DtoDeclareTypeInfo(TypeInfoDeclaration* tid)
{
    DtoResolveTypeInfo(tid);

    if (tid->ir.declared) return;
    tid->ir.declared = true;

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

    if (Logger::enabled())
    {
        std::string mangled(tid->mangle());
        Logger::println("type = '%s'", tid->tinfo->toChars());
        Logger::println("typeinfo mangle: %s", mangled.c_str());
    }

    IrGlobal* irg = tid->ir.irGlobal;
    assert(irg->value != NULL);

    // this is a declaration of a builtin __initZ var
    if (tid->tinfo->builtinTypeInfo()) {
        LLGlobalVariable* g = isaGlobalVar(irg->value);
        g->setLinkage(llvm::GlobalValue::ExternalLinkage);
        return;
    }

    // define custom typedef
    tid->llvmDefine();
}

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

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

    RTTIBuilder b(Type::typeinfo);
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfotypedef);

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

    // TypeInfo base
    sd->basetype = sd->basetype->merge(); // dmd does it ... why?
    b.push_typeinfo(sd->basetype);

    // char[] name
    b.push_string(sd->toPrettyChars());

    // void[] init
    // emit null array if we should use the basetype, or if the basetype
    // uses default initialization.
    if (tinfo->isZeroInit(0) || !sd->init)
    {
        b.push_null_void_array();
    }
    // otherwise emit a void[] with the default initializer
    else
    {
        LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init);
        b.push_void_array(C, sd->basetype, sd);
    }

    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfoenum);

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

    // TypeInfo base
    b.push_typeinfo(sd->memtype);

    // char[] name
    b.push_string(sd->toPrettyChars());

    // void[] init
    // emit void[] with the default initialier, the array is null if the default
    // initializer is zero
    if (!sd->defaultval || tinfo->isZeroInit(0))
    {
        b.push_null_void_array();
    }
    // otherwise emit a void[] with the default initializer
    else
    {
        LLType* memty = DtoType(sd->memtype);
#if DMDV2
        LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !isLLVMUnsigned(sd->memtype));
#else
        LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !isLLVMUnsigned(sd->memtype));
#endif
        b.push_void_array(C, sd->memtype, sd);
    }

    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfopointer);
    // TypeInfo base
    b.push_typeinfo(tinfo->nextOf());
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfoarray);
    // TypeInfo base
    b.push_typeinfo(tinfo->nextOf());
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    assert(tinfo->ty == Tsarray);
    TypeSArray *tc = static_cast<TypeSArray *>(tinfo);

    RTTIBuilder b(Type::typeinfostaticarray);

    // value typeinfo
    b.push_typeinfo(tc->nextOf());

    // length
    b.push(DtoConstSize_t(static_cast<size_t>(tc->dim->toUInteger())));

    // finish
    b.finalize(ir.irGlobal);
}

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

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

    assert(tinfo->ty == Taarray);
    TypeAArray *tc = static_cast<TypeAArray *>(tinfo);

    RTTIBuilder b(Type::typeinfoassociativearray);

    // value typeinfo
    b.push_typeinfo(tc->nextOf());

    // key typeinfo
    b.push_typeinfo(tc->index);

#if DMDV2
    // impl typeinfo
    b.push_typeinfo(tc->getImpl()->type);
#endif

    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfofunction);
    // TypeInfo base
    b.push_typeinfo(tinfo->nextOf());
    // string deco
    b.push_string(tinfo->deco);
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    assert(tinfo->ty == Tdelegate);
    Type* ret_type = tinfo->nextOf()->nextOf();

    RTTIBuilder b(Type::typeinfodelegate);
    // TypeInfo base
    b.push_typeinfo(ret_type);
    // string deco
    b.push_string(tinfo->deco);
    // finish
    b.finalize(ir.irGlobal);
}

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

static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod)
{
    Dsymbol *s = search_function(ad, id);
    FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {
        FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod);
        if (fd)
        {
            return fd;
        }
    }
    return NULL;
}

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

    // make sure struct is resolved
    assert(tinfo->ty == Tstruct);
    TypeStruct *tc = static_cast<TypeStruct *>(tinfo);
    StructDeclaration *sd = tc->sym;

    // can't emit typeinfo for forward declarations
    if (sd->sizeok != 1)
    {
        sd->error("cannot emit TypeInfo for forward declaration");
        fatal();
    }

    sd->codegen(Type::sir);
    IrStruct* irstruct = sd->ir.irStruct;

    RTTIBuilder b(Type::typeinfostruct);

    // char[] name
    b.push_string(sd->toPrettyChars());

    // void[] init
    // never emit a null array, even for zero initialized typeinfo
    // the size() method uses this array!
    size_t init_size = getTypeStoreSize(tc->irtype->getLLType());
    b.push_void_array(init_size, irstruct->getInitSymbol());

    // toX functions ground work
    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
        Scope sc;
        tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
#if DMDV2
        tftohash ->mod = MODconst;
#endif
        tftohash = static_cast<TypeFunction *>(tftohash->semantic(0, &sc));

#if DMDV2
        Type *retType = Type::tchar->invariantOf()->arrayOf();
#else
        Type *retType = Type::tchar->arrayOf();
#endif
        tftostring = new TypeFunction(NULL, retType, 0, LINKd);
        tftostring = static_cast<TypeFunction *>(tftostring->semantic(0, &sc));
    }

    // this one takes a parameter, so we need to build a new one each time
    // to get the right type. can we avoid this?
    TypeFunction *tfcmpptr;
    {
        Scope sc;
        Parameters *arguments = new Parameters;
#if STRUCTTHISREF
        // arg type is ref const T
        Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL);
#else
        // arg type is const T*
        Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL);
#endif
        arguments->push(arg);
        tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
#if DMDV2
        tfcmpptr->mod = MODconst;
#endif
        tfcmpptr = static_cast<TypeFunction *>(tfcmpptr->semantic(0, &sc));
    }

    // well use this module for all overload lookups
    Module *gm = getModule();

    // toHash
    FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm);
    b.push_funcptr(fd);

    // opEquals
#if DMDV2
    fd = sd->xeq;
#else
    fd = find_method_overload(sd, Id::eq, tfcmpptr, gm);
#endif
    b.push_funcptr(fd);

    // opCmp
    fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm);
    b.push_funcptr(fd);

    // toString
    fd = find_method_overload(sd, Id::tostring, tftostring, gm);
    b.push_funcptr(fd);

    // uint m_flags;
    unsigned hasptrs = tc->hasPointers() ? 1 : 0;
    b.push_uint(hasptrs);

#if DMDV2

    ClassDeclaration* tscd = Type::typeinfostruct;

    // On x86_64, class TypeInfo_Struct contains 2 additional fields
    // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs 
    // implementation. They are not present on any other cpu/os.
    assert((global.params.cpu != ARCHx86_64 && tscd->fields.dim == 11) ||
           (global.params.cpu == ARCHx86_64 && tscd->fields.dim == 13));

    //void function(void*)                    xdtor;
    b.push_funcptr(sd->dtor);

    //void function(void*)                    xpostblit;
    FuncDeclaration *xpostblit = sd->postblit;
    if (xpostblit && sd->postblit->storage_class & STCdisable)
        xpostblit = 0;
    b.push_funcptr(xpostblit);

    //uint m_align;
    b.push_uint(tc->alignsize());

    if (global.params.is64bit)
    {
        // TypeInfo m_arg1;
        // TypeInfo m_arg2;
        TypeTuple *tup = tc->toArgTypes();
        assert(tup->arguments->dim <= 2);
        for (unsigned i = 0; i < 2; i++)
        {
            if (i < tup->arguments->dim)
            {
                Type *targ = static_cast<Parameter *>(tup->arguments->data[i])->type;
                targ = targ->merge();
                b.push_typeinfo(targ);
            }
            else
                b.push_null(Type::typeinfo->type);
        }
    }

    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (sd->getRTInfo)
        b.push(sd->getRTInfo->toConstElem(gIR));
    else if (!tc->hasPointers())
        b.push_size_as_vp(0);       // no pointers
    else
        b.push_size_as_vp(1);       // has pointers

#endif

    // finish
    b.finalize(ir.irGlobal);
}

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

#if DMDV2
void TypeInfoClassDeclaration::codegen(Ir*i)
{

    IrGlobal* irg = new IrGlobal(this);
    ir.irGlobal = irg;
    assert(tinfo->ty == Tclass);
    TypeClass *tc = static_cast<TypeClass *>(tinfo);
    tc->sym->codegen(Type::sir); // make sure class is resolved
    irg->value = tc->sym->ir.irStruct->getClassInfoSymbol();
}
#endif

void TypeInfoClassDeclaration::llvmDefine()
{
#if DMDV2
    assert(0);
#endif
    Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    // make sure class is resolved
    assert(tinfo->ty == Tclass);
    TypeClass *tc = static_cast<TypeClass *>(tinfo);
    tc->sym->codegen(Type::sir);

    RTTIBuilder b(Type::typeinfoclass);

    // TypeInfo base
    b.push_classinfo(tc->sym);

    // finish
    b.finalize(ir.irGlobal);
}

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

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

    // make sure interface is resolved
    assert(tinfo->ty == Tclass);
    TypeClass *tc = static_cast<TypeClass *>(tinfo);
    tc->sym->codegen(Type::sir);

    RTTIBuilder b(Type::typeinfointerface);

    // TypeInfo base
    b.push_classinfo(tc->sym);

    // finish
    b.finalize(ir.irGlobal);
}

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

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

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

    size_t dim = tu->arguments->dim;
    std::vector<LLConstant*> arrInits;
    arrInits.reserve(dim);

    LLType* tiTy = DtoType(Type::typeinfo->type);

    for (size_t i = 0; i < dim; i++)
    {
        Parameter *arg = static_cast<Parameter *>(tu->arguments->data[i]);
        arrInits.push_back(DtoTypeInfoOf(arg->type, true));
    }

    // build array
    LLArrayType* arrTy = LLArrayType::get(tiTy, dim);
    LLConstant* arrC = LLConstantArray::get(arrTy, arrInits);

    RTTIBuilder b(Type::typeinfotypelist);

    // push TypeInfo[]
    b.push_array(arrC, dim, Type::typeinfo->type, NULL);

    // finish
    b.finalize(ir.irGlobal);
}

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

#if DMDV2

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

    RTTIBuilder b(Type::typeinfoconst);
    // TypeInfo base
    b.push_typeinfo(tinfo->mutableOf()->merge());
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfoinvariant);
    // TypeInfo base
    b.push_typeinfo(tinfo->mutableOf()->merge());
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfoshared);
    // TypeInfo base
    b.push_typeinfo(tinfo->unSharedOf()->merge());
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    RTTIBuilder b(Type::typeinfowild);
    // TypeInfo base
    b.push_typeinfo(tinfo->mutableOf()->merge());
    // finish
    b.finalize(ir.irGlobal);
}

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

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

    assert(tinfo->ty == Tvector);
    TypeVector *tv = static_cast<TypeVector *>(tinfo);

    RTTIBuilder b(Type::typeinfovector);
    // TypeInfo base
    b.push_typeinfo(tv->basetype);
    // finish
    b.finalize(ir.irGlobal);
}

#endif
