diff ir/irclass.cpp @ 1228:79758fd2f48a

Added Doxygen file. Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete.
author Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
date Wed, 15 Apr 2009 20:06:25 +0200
parents
children fafe7c8d6734
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ir/irclass.cpp	Wed Apr 15 20:06:25 2009 +0200
@@ -0,0 +1,441 @@
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+
+#include "aggregate.h"
+#include "declaration.h"
+#include "mtype.h"
+
+#include "gen/irstate.h"
+#include "gen/logger.h"
+#include "gen/tollvm.h"
+#include "gen/llvmhelpers.h"
+#include "gen/utils.h"
+#include "gen/arrays.h"
+
+#include "ir/irstruct.h"
+#include "ir/irtypeclass.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init);
+extern size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff);
+
+extern LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLGlobalVariable * IrStruct::getVtblSymbol()
+{
+    if (vtbl)
+        return vtbl;
+
+    // create the initZ symbol
+    std::string initname("_D");
+    initname.append(aggrdecl->mangle());
+    initname.append("6__vtblZ");
+
+    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
+
+    const LLType* vtblTy = type->irtype->isClass()->getVtbl();
+
+    vtbl = new llvm::GlobalVariable(
+        vtblTy, true, _linkage, NULL, initname, gIR->module);
+
+    return vtbl;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLGlobalVariable * IrStruct::getClassInfoSymbol()
+{
+    if (classInfo)
+        return classInfo;
+
+    // create the initZ symbol
+    std::string initname("_D");
+    initname.append(aggrdecl->mangle());
+    if (aggrdecl->isInterfaceDeclaration())
+        initname.append("11__InterfaceZ");
+    else
+        initname.append("7__ClassZ");
+
+    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
+
+    ClassDeclaration* cinfo = ClassDeclaration::classinfo;
+    DtoType(cinfo->type);
+    IrTypeClass* tc = cinfo->type->irtype->isClass();
+    assert(tc && "invalid ClassInfo type");
+
+    classInfo = new llvm::GlobalVariable(
+        tc->getPA().get(), true, _linkage, NULL, initname, gIR->module);
+
+    return classInfo;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLGlobalVariable * IrStruct::getInterfaceArraySymbol()
+{
+    if (classInterfacesArray)
+        return classInterfacesArray;
+
+    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
+
+    assert(cd->vtblInterfaces && cd->vtblInterfaces->dim > 0 &&
+        "should not create interface info array for class with no explicit "
+        "interface implementations")
+
+    VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3);
+    const llvm::Type* InterfaceTy = DtoType(idx->type);
+
+    // create Interface[N]
+    const llvm::ArrayType* array_type = llvm::ArrayType::get(
+        InterfaceTy,
+        cd->vtblInterfaces->dim);
+
+    // put it in a global
+    std::string name("_D");
+    name.append(cd->mangle());
+    name.append("16__interfaceInfosZ");
+    classInterfacesArray = new llvm::GlobalVariable(array_type, true, DtoLinkage(cd), NULL, name, classInfo);
+
+    return classInterfacesArray;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLConstant * IrStruct::getVtblInit()
+{
+    if (constVtbl)
+        return constVtbl;
+
+    IF_LOG Logger::println("Building vtbl initializer");
+    LOG_SCOPE;
+
+    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
+    assert(cd && "not class");
+
+    std::vector<llvm::Constant*> constants;
+    constants.reserve(cd->vtbl.dim);
+
+    // start with the classinfo
+    llvm::Constant* c = getClassInfoSymbol();
+    c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type));
+    constants.push_back(c);
+
+    // add virtual function pointers
+    size_t n = cd->vtbl.dim;
+    for (size_t i = 1; i < n; i++)
+    {
+        Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[i];
+        assert(dsym && "null vtbl member");
+
+        FuncDeclaration* fd = dsym->isFuncDeclaration();
+        assert(fd && "vtbl entry not a function");
+
+        if (fd->isAbstract() && !fd->fbody)
+        {
+            c = getNullValue(DtoType(fd->type->pointerTo()));
+        }
+        else
+        {
+            fd->codegen(Type::sir);
+            assert(fd->ir.irFunc && "invalid vtbl function");
+            c = fd->ir.irFunc->func;
+        }
+        constants.push_back(c);
+    }
+
+    // build the constant struct
+    constVtbl = llvm::ConstantStruct::get(constants, false);
+
+    // sanity check
+#if 0
+    IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl;
+    IF_LOG Logger::cout() << "vtbl type: " << *type->irtype->isClass()->getVtbl() << std::endl;
+#endif
+
+    assert(constVtbl->getType() == type->irtype->isClass()->getVtbl() &&
+        "vtbl initializer type mismatch");
+
+    return constVtbl;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLConstant * IrStruct::getClassInfoInit()
+{
+    if (constClassInfo)
+        return constClassInfo;
+    constClassInfo = DtoDefineClassInfo(aggrdecl->isClassDeclaration());
+    return constClassInfo;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void IrStruct::addBaseClassInits(
+    std::vector<llvm::Constant*>& constants,
+    ClassDeclaration* base,
+    size_t& offset,
+    size_t& field_index)
+{
+    if (base->baseClass)
+    {
+        addBaseClassInits(constants, base->baseClass, offset, field_index);
+    }
+
+    ArrayIter<VarDeclaration> it(base->fields);
+    for (; !it.done(); it.next())
+    {
+        VarDeclaration* vd = it.get();
+
+        // skip if offset moved backwards
+        if (vd->offset < offset)
+        {
+            IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset);
+            continue;
+        }
+
+        IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
+        LOG_SCOPE;
+
+        // get next aligned offset for this type
+        size_t alignsize = vd->type->alignsize();
+        size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
+
+        // insert explicit padding?
+        if (alignedoffset < vd->offset)
+        {
+            add_zeros(constants, vd->offset - alignedoffset);
+        }
+
+        // add default type
+        constants.push_back(get_default_initializer(vd, vd->init));
+
+        // advance offset to right past this field
+        offset = vd->offset + vd->type->size();
+    }
+
+    // has interface vtbls?
+    if (base->vtblInterfaces)
+    {
+        // false when it's not okay to use functions from super classes
+        bool newinsts = (base == aggrdecl->isClassDeclaration());
+
+        ArrayIter<BaseClass> it2(*base->vtblInterfaces);
+        for (; !it2.done(); it2.next())
+        {
+            BaseClass* b = it2.get();
+            constants.push_back(getInterfaceVtbl(b, newinsts));
+            offset += PTRSIZE;
+        }
+    }
+
+    // tail padding?
+    if (offset < base->structsize)
+    {
+        add_zeros(constants, base->structsize - offset);
+        offset = base->structsize;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLConstant * IrStruct::createClassDefaultInitializer()
+{
+    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
+    assert(cd && "invalid class aggregate");
+
+    IF_LOG Logger::println("Building class default initializer %s @ %s", cd->toPrettyChars(), cd->locToChars());
+    LOG_SCOPE;
+    IF_LOG Logger::println("Instance size: %u", cd->structsize);
+
+    // find the fields that contribute to the default initializer.
+    // these will define the default type.
+
+    std::vector<llvm::Constant*> constants;
+    constants.reserve(32);
+
+    // add vtbl
+    constants.push_back(getVtblSymbol());
+    // add monitor
+    constants.push_back(getNullValue(DtoType(Type::tvoid->pointerTo())));
+
+    // we start right after the vtbl and monitor
+    size_t offset = PTRSIZE * 2;
+    size_t field_index = 2;
+
+    // add data members recursively
+    addBaseClassInits(constants, cd, offset, field_index);
+
+    // build the constant
+    llvm::Constant* definit = llvm::ConstantStruct::get(constants, false);
+
+    // sanity check
+    assert(definit->getType() == type->irtype->getPA().get() && "class initializer type mismatch");
+
+    return definit;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance)
+{
+    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
+    assert(cd && "not a class aggregate");
+
+    ClassGlobalMap::iterator it = interfaceVtblMap.find(cd);
+    if (it != interfaceVtblMap.end())
+        return it->second;
+
+    IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s",
+        b->base->toPrettyChars(), aggrdecl->toPrettyChars());
+    LOG_SCOPE;
+
+    Array vtbl_array;
+    b->fillVtbl(cd, &vtbl_array, new_instance);
+
+    std::vector<llvm::Constant*> constants;
+    constants.reserve(vtbl_array.dim);
+
+    // start with the interface info
+    llvm::Constant* c = getNullValue(DtoType(Type::tvoid->pointerTo()));
+    constants.push_back(c);
+
+    // add virtual function pointers
+    size_t n = vtbl_array.dim;
+    for (size_t i = 1; i < n; i++)
+    {
+        Dsymbol* dsym = (Dsymbol*)vtbl_array.data[i];
+        assert(dsym && "null vtbl member");
+
+        FuncDeclaration* fd = dsym->isFuncDeclaration();
+        assert(fd && "vtbl entry not a function");
+
+        assert(!(fd->isAbstract() && !fd->fbody) &&
+            "null symbol in interface implementation vtable");
+
+        fd->codegen(Type::sir);
+        assert(fd->ir.irFunc && "invalid vtbl function");
+
+        constants.push_back(fd->ir.irFunc->func);
+    }
+
+    // build the vtbl constant
+    llvm::Constant* vtbl_constant = llvm::ConstantStruct::get(constants, false);
+
+    // create the global variable to hold it
+    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
+
+    std::string mangle("_D");
+    mangle.append(cd->mangle());
+    mangle.append("11__interface");
+    mangle.append(b->base->mangle());
+    mangle.append("6__vtblZ");
+
+    llvm::GlobalVariable* GV = new llvm::GlobalVariable(
+        vtbl_constant->getType(),
+        true,
+        _linkage,
+        vtbl_constant,
+        mangle,
+        gIR->module
+    );
+
+    interfaceVtblMap.insert(std::make_pair(b->base, GV));
+
+    return GV;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLConstant * IrStruct::getClassInfoInterfaces()
+{
+    IF_LOG Logger::println("Building ClassInfo.interfaces");
+    LOG_SCOPE;
+
+    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
+    assert(cd);
+
+    if (!cd->vtblInterfaces || cd->vtblInterfaces->dim == 0)
+    {
+        VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3);
+        return getNullValue(DtoType(idx->type));
+    }
+
+// Build array of:
+//
+//     struct Interface
+//     {
+//         ClassInfo   classinfo;
+//         void*[]     vtbl;
+//         ptrdiff_t   offset;
+//     }
+
+    LLSmallVector<LLConstant*, 6> constants;
+    constants.reserve(cd->vtblInterfaces->dim);
+
+    const LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type);
+    const LLType* voidptrptr_type = DtoType(
+        Type::tvoid->pointerTo()->pointerTo());
+
+    const LLType* our_type = type->irtype->isClass()->getPA().get();
+
+    ArrayIter<BaseClass> it(*cd->vtblInterfaces);
+    while (it.more())
+    {
+        IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars());
+
+        IrStruct* irinter = it->base->ir.irStruct;
+        assert(irinter && "interface has null IrStruct");
+        IrTypeClass* itc = irinter->type->irtype->isClass();
+        assert(itc && "null interface IrTypeClass");
+
+        // classinfo
+        LLConstant* ci = irinter->getClassInfoSymbol();
+        ci = DtoBitCast(ci, classinfo_type);
+
+        // vtbl
+        ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base);
+        assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
+        LLConstant* vtb = itv->second;
+        vtb = DtoBitCast(vtb, voidptrptr_type);
+        vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb);
+
+        // offset
+        LLConstant* off = DtoConstSize_t(it->offset);
+
+        // create Interface struct
+        LLConstant* inits[3] = { ci, vtb, off };
+        LLConstant* entry = llvm::ConstantStruct::get(inits, 3);
+        constants.push_back(entry);
+
+        // next
+        it.next();
+    }
+
+    // create Interface[N]
+    const llvm::ArrayType* array_type = llvm::ArrayType::get(
+        constants[0]->getType(),
+        cd->vtblInterfaces->dim);
+
+    LLConstant* arr = llvm::ConstantArray::get(
+        array_type,
+        &constants[0],
+        constants.size());
+
+    // apply the initializer
+    classInterfacesArray->setInitializer(arr);
+
+    LLConstant* idxs[2] = {
+        DtoConstSize_t(0),
+        DtoConstSize_t(0)
+    };
+
+    // return as a slice
+    return DtoConstSlice(
+        DtoConstSize_t(cd->vtblInterfaces->dim),
+        llvm::ConstantExpr::getGetElementPtr(classInterfacesArray, idxs, 2));
+}
+
+//////////////////////////////////////////////////////////////////////////////