diff gen/structs.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 ba9d6292572a
children 212ec2d9d176
line wrap: on
line diff
--- a/gen/structs.cpp	Mon Apr 13 17:42:36 2009 +0200
+++ b/gen/structs.cpp	Wed Apr 15 20:06:25 2009 +0200
@@ -15,438 +15,10 @@
 #include "gen/structs.h"
 #include "gen/dvalue.h"
 #include "gen/functions.h"
+#include "gen/utils.h"
 
 #include "ir/irstruct.h"
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// pair of var and its init
-typedef std::pair<VarDeclaration*,Initializer*> VarInitPair;
-
-// comparison func for qsort
-static int varinit_offset_cmp_func(const void* p1, const void* p2)
-{
-    VarDeclaration* v1 = ((VarInitPair*)p1)->first;
-    VarDeclaration* v2 = ((VarInitPair*)p2)->first;
-    if (v1->offset < v2->offset)
-        return -1;
-    else if (v1->offset > v2->offset)
-        return 1;
-    else
-        return 0;
-}
-
-/*
-this uses a simple algorithm to build the correct constant
-
-(1) first sort the explicit initializers by offset... well, DMD doesn't :)
-
-(2) if there is NO space before the next explicit initializeer, goto (9)
-(3) find the next default initializer that fits before it, if NOT found goto (7)
-(4) insert zero padding up to the next default initializer
-(5) insert the next default initializer
-(6) goto (2)
-
-(7) insert zero padding up to the next explicit initializer
-
-(9) insert the next explicit initializer
-(10) goto (2)
-
-(11) done
-
-(next can be the end too)
-
-*/
-
-// return the next default initializer to use or null
-static VarDeclaration* nextDefault(IrStruct* irstruct, size_t& idx, size_t pos, size_t offset)
-{
-    IrStruct::VarDeclVector& defaults = irstruct->defVars;
-    size_t ndefaults = defaults.size();
-
-    // for each valid index
-    while(idx < ndefaults)
-    {
-        VarDeclaration* v = defaults[idx];
-
-        // skip defaults before pos
-        if (v->offset < pos)
-        {
-            idx++;
-            continue;
-        }
-
-        // this var default fits
-        if (v->offset >= pos && v->offset + v->type->size() <= offset)
-            return v;
-
-        // not usable
-        break;
-    }
-
-    // not usable
-    return NULL;
-}
-
-LLConstant* DtoConstStructInitializer(StructInitializer* si)
-{
-    Logger::println("DtoConstStructInitializer: %s", si->toChars());
-    LOG_SCOPE;
-
-    // get TypeStruct
-    assert(si->ad);
-    TypeStruct* ts = (TypeStruct*)si->ad->type;
-
-    // force constant initialization of the symbol
-    si->ad->codegen(Type::sir);
-
-    // sanity check
-    assert(si->value.dim > 0);
-    assert(si->value.dim == si->vars.dim);
-
-    // vector of final initializer constants
-    std::vector<LLConstant*> inits;
-
-    // get the ir struct
-    IrStruct* irstruct = si->ad->ir.irStruct;
-
-    // get default fields
-    IrStruct::VarDeclVector& defaults = irstruct->defVars;
-    size_t ndefaults = defaults.size();
-
-    // make sure si->vars is sorted by offset
-    std::vector<VarInitPair> vars;
-    size_t nvars = si->vars.dim;
-    vars.resize(nvars);
-
-    // fill pair vector
-    for (size_t i = 0; i < nvars; i++)
-    {
-        VarDeclaration* var = (VarDeclaration*)si->vars.data[i];
-        Initializer* ini = (Initializer*)si->value.data[i];
-        assert(var);
-        assert(ini);
-        vars[i] = std::make_pair(var, ini);
-    }
-    // sort it
-    qsort(&vars[0], nvars, sizeof(VarInitPair), &varinit_offset_cmp_func);
-
-    // check integrity
-    // and do error checking, since the frontend does not verify static struct initializers
-    size_t lastoffset = 0;
-    size_t lastsize = 0;
-    bool overlap = false;
-    for (size_t i=0; i < nvars; i++)
-    {
-        // next explicit init var
-        VarDeclaration* var = vars[i].first;
-        Logger::println("var = %s : +%u", var->toChars(), var->offset);
-
-        // I would have thought this to be a frontend check
-        for (size_t j=i+1; j<nvars; j++)
-        {
-            if (j == i)
-                continue;
-            VarDeclaration* var2 = vars[j].first;
-            if (var2->offset >= var->offset && var2->offset < var->offset + var->type->size())
-            {
-                fprintf(stdmsg, "Error: %s: initializer '%s' overlaps with '%s'\n", si->loc.toChars(), var->toChars(), var2->toChars());
-                overlap = true;
-            }
-        }
-
-        // update offsets
-        lastoffset = var->offset;
-        lastsize = var->type->size();
-    }
-
-    // error handling, report all overlaps before aborting
-    if (overlap)
-    {
-        error("%s: overlapping union initializers", si->loc.toChars());
-    }
-
-    // go through each explicit initalizer, falling back to defaults or zeros when necessary
-    lastoffset = 0;
-    lastsize = 0;
-
-    size_t j=0; // defaults
-
-    for (size_t i=0; i < nvars; i++)
-    {
-        // get var and init
-        VarDeclaration* var = vars[i].first;
-        Initializer* ini = vars[i].second;
-
-        size_t offset = var->offset;
-        size_t size = var->type->size();
-
-        // if there is space before the next explicit initializer
-Lpadding:
-        size_t pos = lastoffset+lastsize;
-        if (offset > pos)
-        {
-            // find the the next default initializer that fits in this space
-            VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, offset);
-
-            // found
-            if (nextdef)
-            {
-                // need zeros before the default
-                if (nextdef->offset > pos)
-                {
-                    Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos);
-                    addZeros(inits, pos, nextdef->offset);
-                }
-
-                // do the default
-                Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset);
-                if (!nextdef->ir.irField->constInit)
-                    nextdef->ir.irField->constInit = DtoConstInitializer(nextdef->loc, nextdef->type, nextdef->init);
-                LLConstant* c = nextdef->ir.irField->constInit;
-                inits.push_back(c);
-
-                // update offsets
-                lastoffset = nextdef->offset;
-                lastsize = nextdef->type->size();
-
-                // check if more defaults would fit
-                goto Lpadding;
-            }
-            // not found, pad with zeros
-            else
-            {
-                Logger::println("inserting %lu byte padding at %lu", offset - pos, pos);
-                addZeros(inits, pos, offset);
-                // offsets are updated by the explicit initializer
-            }
-        }
-
-        // insert next explicit
-        Logger::println("adding explicit field: %s : +%lu", var->toChars(), offset);
-        LOG_SCOPE;
-        LLConstant* c = DtoConstInitializer(var->loc, var->type, ini);
-        inits.push_back(c);
-
-        lastoffset = offset;
-        lastsize = size;
-    }
-
-    // there might still be padding after the last one, make sure that is defaulted/zeroed as well
-    size_t structsize = si->ad->structsize;
-
-    // if there is space before the next explicit initializer
-    // FIXME: this should be handled in the loop above as well
-Lpadding2:
-    size_t pos = lastoffset+lastsize;
-    if (structsize > pos)
-    {
-        // find the the next default initializer that fits in this space
-        VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, structsize);
-
-        // found
-        if (nextdef)
-        {
-            // need zeros before the default
-            if (nextdef->offset > pos)
-            {
-                Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos);
-                addZeros(inits, pos, nextdef->offset);
-            }
-
-            // do the default
-            Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset);
-            if (!nextdef->ir.irField->constInit)
-                nextdef->ir.irField->constInit = DtoConstInitializer(nextdef->loc, nextdef->type, nextdef->init);
-            LLConstant* c = nextdef->ir.irField->constInit;
-            inits.push_back(c);
-
-            // update offsets
-            lastoffset = nextdef->offset;
-            lastsize = nextdef->type->size();
-
-            // check if more defaults would fit
-            goto Lpadding2;
-        }
-        // not found, pad with zeros
-        else
-        {
-            Logger::println("inserting %lu byte padding at %lu", structsize - pos, pos);
-            addZeros(inits, pos, structsize);
-            lastoffset = pos;
-            lastsize = structsize - pos;
-        }
-    }
-
-    assert(lastoffset+lastsize == structsize);
-
-    // make the constant struct
-    LLConstant* c = LLConstantStruct::get(inits, si->ad->ir.irStruct->packed);
-    if (Logger::enabled())
-    {
-        Logger::cout() << "constant struct initializer: " << *c << '\n';
-    }
-    assert(getTypePaddedSize(c->getType()) == structsize);
-    return c;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& inits)
-{
-    // get arrays 
-    size_t nvars = sd->fields.dim;
-    VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
-
-    assert(inits.size() == nvars);
-
-    // first locate all explicit initializers
-    std::vector<VarDeclaration*> explicitInits;
-    for (size_t i=0; i < nvars; i++)
-    {
-        if (inits[i])
-        {
-            explicitInits.push_back(vars[i]);
-        }
-    }
-
-    // vector of values to build aggregate from
-    std::vector<llvm::Value*> values;
-
-    // offset trackers
-    size_t lastoffset = 0;
-    size_t lastsize = 0;
-
-    // index of next explicit init
-    size_t exidx = 0;
-    // number of explicit inits
-    size_t nex = explicitInits.size();
-
-    // for through each field and build up the struct, padding with zeros
-    size_t i;
-    for (i=0; i<nvars; i++)
-    {
-        VarDeclaration* var = vars[i];
-
-        // get var info
-        size_t os = var->offset;
-        size_t sz = var->type->size();
-
-        // get next explicit
-        VarDeclaration* nextVar = NULL;
-        size_t nextOs = 0;
-        if (exidx < nex)
-        {
-            nextVar = explicitInits[exidx];
-            nextOs = nextVar->offset;
-        }
-        // none, rest is defaults
-        else
-        {
-            break;
-        }
-
-        // not explicit initializer, default initialize if there is room, otherwise skip
-        if (!inits[i])
-        {
-            // default init if there is room
-            // (past current offset) and (small enough to fit before next explicit)
-            if ((os >= lastoffset + lastsize) && (os+sz <= nextOs))
-            {
-                // add any 0 padding needed before this field
-                if (os > lastoffset + lastsize)
-                {
-                    //printf("1added %lu zeros\n", os - lastoffset - lastsize);
-                    addZeros(values, lastoffset + lastsize, os);
-                }
-
-                // get field default init
-                IrField* f = var->ir.irField;
-                assert(f);
-                if (!f->constInit)
-                    f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
-
-                values.push_back(f->constInit);
-
-                lastoffset = os;
-                lastsize = sz;
-                //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
-            }
-            // skip
-            continue;
-        }
-
-        assert(nextVar == var);
-
-        // add any 0 padding needed before this field
-        if (os > lastoffset + lastsize)
-        {
-            //printf("added %lu zeros\n", os - lastoffset - lastsize);
-            addZeros(values, lastoffset + lastsize, os);
-        }
-
-        // add the expression value
-        values.push_back(inits[i]);
-
-        // update offsets
-        lastoffset = os;
-        lastsize = sz;
-
-        // go to next explicit init
-        exidx++;
-
-        //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz);
-    }
-
-    // fill out rest with default initializers
-    const LLType* structtype = DtoType(sd->type);
-    size_t structsize = getTypePaddedSize(structtype);
-
-    // FIXME: this could probably share some code with the above
-    if (structsize > lastoffset+lastsize)
-    {
-        for (/*continue from first loop*/; i < nvars; i++)
-        {
-            VarDeclaration* var = vars[i];
-
-            // get var info
-            size_t os = var->offset;
-            size_t sz = var->type->size();
-
-            // skip?
-            if (os < lastoffset + lastsize)
-                continue;
-
-            // add any 0 padding needed before this field
-            if (os > lastoffset + lastsize)
-            {
-                //printf("2added %lu zeros\n", os - lastoffset - lastsize);
-                addZeros(values, lastoffset + lastsize, os);
-            }
-
-            // get field default init
-            IrField* f = var->ir.irField;
-            assert(f);
-            if (!f->constInit)
-                f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
-
-            values.push_back(f->constInit);
-
-            lastoffset = os;
-            lastsize = sz;
-            //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
-        }
-    }
-
-    // add any 0 padding needed at the end of the literal
-    if (structsize > lastoffset+lastsize)
-    {
-        //printf("3added %lu zeros\n", structsize - lastoffset - lastsize);
-        addZeros(values, lastoffset + lastsize, structsize);
-    }
-
-    return values;
-}
+#include "ir/irtypestruct.h"
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -490,10 +62,6 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-static void DtoDeclareStruct(StructDeclaration* sd);
-static void DtoConstInitStruct(StructDeclaration* sd);
-static void DtoDefineStruct(StructDeclaration* sd);
-
 void DtoResolveStruct(StructDeclaration* sd)
 {
     // don't do anything if already been here
@@ -505,185 +73,38 @@
     Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->locToChars());
     LOG_SCOPE;
 
-    // get the DMD TypeStruct
-    TypeStruct* ts = (TypeStruct*)sd->type;
+    // make sure type exists
+    DtoType(sd->type);
 
     // create the IrStruct
     IrStruct* irstruct = new IrStruct(sd);
     sd->ir.irStruct = irstruct;
 
-    // create the type
-    ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get());
-
-    // create symbols we're going to need
-    // avoids chicken egg problems
-    std::string initname("_D");
-    initname.append(sd->mangle());
-    initname.append("6__initZ");
-
-    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(sd);
-    sd->ir.irStruct->init = new llvm::GlobalVariable(sd->ir.irStruct->initOpaque.get(), true, _linkage, NULL, initname, gIR->module);
-
-    // handle forward declaration structs (opaques)
-    // didn't even know D had those ...
-    if (sd->sizeok != 1)
-    {
-        // nothing more to do
-        return;
-    }
-
-    // make this struct current
-    gIR->structs.push_back(irstruct);
-
-    // get some info
-    bool ispacked = (ts->alignsize() == 1);
-
-    // set irstruct info
-    irstruct->packed = ispacked;
+    // emit the initZ symbol
+    LLGlobalVariable* initZ = irstruct->getInitSymbol();
 
-    // methods, fields
-    Array* arr = sd->members;
-    for (int k=0; k < arr->dim; k++) {
-        Dsymbol* s = (Dsymbol*)arr->data[k];
-        s->codegen(Type::sir);
-    }
-
-    const LLType* ST = irstruct->build();
-
-#if 0
-    std::cout << sd->kind() << ' ' << sd->toPrettyChars() << " type: " << *ST << '\n';
-
-    // add fields
-    for (int k=0; k < fields->dim; k++)
+    // perform definition
+    if (mustDefineSymbol(sd))
     {
-        VarDeclaration* v = (VarDeclaration*)fields->data[k];
-        printf("  field: %s %s\n", v->type->toChars(), v->toChars());
-        printf("    index: %u offset: %u\n", v->ir.irField->index, v->ir.irField->unionOffset);
-    }
-
-    unsigned llvmSize = (unsigned)getTypePaddedSize(ST);
-    unsigned dmdSize = (unsigned)sd->type->size();
-    printf("  llvm size: %u     dmd size: %u\n", llvmSize, dmdSize);
-    assert(llvmSize == dmdSize);
-
-#endif
-
-    /*for (int k=0; k < sd->members->dim; k++) {
-        Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]);
-        dsym->toObjFile();
-    }*/
-
-    Logger::println("doing struct fields");
-
-    // refine abstract types for stuff like: struct S{S* next;}
-    llvm::cast<llvm::OpaqueType>(ts->ir.type->get())->refineAbstractTypeTo(ST);
-    ST = ts->ir.type->get();
-
-    // name type
-    if (sd->parent->isModule()) {
-        gIR->module->addTypeName(sd->mangle(),ST);
+        // set initZ initializer
+        initZ->setInitializer(irstruct->getDefaultInit());
     }
 
-    // emit functions
-    size_t n = irstruct->structFuncs.size();
-    for (size_t i = 0; i < n; ++i)
+    // emit members
+    if (sd->members)
     {
-        DtoResolveFunction(irstruct->structFuncs[i]);
-    }
-    irstruct->structFuncs.clear();
-
-    gIR->structs.pop_back();
-
-    DtoDeclareStruct(sd);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static void DtoDeclareStruct(StructDeclaration* sd)
-{
-    DtoResolveStruct(sd);
-
-    if (sd->ir.declared) return;
-    sd->ir.declared = true;
-
-    Logger::println("DtoDeclareStruct(%s): %s", sd->toChars(), sd->loc.toChars());
-    LOG_SCOPE;
-
-    TypeStruct* ts = (TypeStruct*)sd->type->toBasetype();
-
-    DtoConstInitStruct(sd);
-    if (mustDefineSymbol(sd))
-        DtoDefineStruct(sd);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static void DtoConstInitStruct(StructDeclaration* sd)
-{
-    DtoDeclareStruct(sd);
-
-    if (sd->ir.initialized) return;
-    sd->ir.initialized = true;
-
-    Logger::println("DtoConstInitStruct(%s): %s", sd->toChars(), sd->loc.toChars());
-    LOG_SCOPE;
-
-    IrStruct* irstruct = sd->ir.irStruct;
-    gIR->structs.push_back(irstruct);
-
-    const llvm::StructType* structtype = isaStruct(sd->type->ir.type->get());
-
-    // always generate the constant initalizer
-    assert(!irstruct->constInit);
-    if (sd->zeroInit)
-    {
-        Logger::println("Zero initialized");
-        irstruct->constInit = llvm::ConstantAggregateZero::get(structtype);
-    }
-    else
-    {
-        Logger::println("Not zero initialized");
-
-        LLConstant* c = irstruct->buildDefaultConstInit();
-        irstruct->constInit = c;
+        ArrayIter<Dsymbol> it(*sd->members);
+        while (!it.done())
+        {
+            Dsymbol* member = it.get();
+            if (member)
+                member->codegen(Type::sir);
+            it.next();
+        }
     }
 
-    // refine __initZ global type to the one of the initializer
-    llvm::cast<llvm::OpaqueType>(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType());
-
-    // build initializers for static member variables
-    size_t n = irstruct->staticVars.size();
-    for (size_t i = 0; i < n; ++i)
-    {
-        DtoConstInitGlobal(irstruct->staticVars[i]);
-    }
-    // This is all we use it for. Clear the memory!
-    irstruct->staticVars.clear(); 
-
-    gIR->structs.pop_back();
-
     // emit typeinfo
-    if (sd->getModule() == gIR->dmodule && sd->llvmInternal != LLVMno_typeinfo)
-        DtoTypeInfoOf(sd->type, false);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static void DtoDefineStruct(StructDeclaration* sd)
-{
-    DtoConstInitStruct(sd);
-
-    if (sd->ir.defined) return;
-    sd->ir.defined = true;
-
-    Logger::println("DtoDefineStruct(%s): %s", sd->toChars(), sd->loc.toChars());
-    LOG_SCOPE;
-
-    assert(sd->type->ty == Tstruct);
-    TypeStruct* ts = (TypeStruct*)sd->type;
-    sd->ir.irStruct->init->setInitializer(sd->ir.irStruct->constInit);
-
-    sd->ir.DModule = gIR->dmodule;
+    DtoTypeInfoOf(sd->type);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////