mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 02:06:35 +01:00
Added Doxygen file.
Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete.
This commit is contained in:
@@ -115,10 +115,6 @@ struct AnonDeclaration : AttribDeclaration
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
const char *kind();
|
||||
|
||||
#if IN_LLVM
|
||||
void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct PragmaDeclaration : AttribDeclaration
|
||||
|
||||
@@ -55,7 +55,6 @@ int isnan(double);
|
||||
#include "hdrgen.h"
|
||||
#include "parse.h"
|
||||
|
||||
Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim);
|
||||
Expression *expandVar(int result, VarDeclaration *v);
|
||||
|
||||
#define LOGSEMANTIC 0
|
||||
|
||||
19
dmd/func.c
19
dmd/func.c
@@ -84,6 +84,25 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||
// LDC
|
||||
isArrayOp = false;
|
||||
allowInlining = false;
|
||||
|
||||
// function types in ldc don't merge if the context parameter differs
|
||||
// so we actually don't care about the function declaration, but only
|
||||
// what kind of context parameter it has.
|
||||
// however, this constructor is usually called from the parser, which
|
||||
// unfortunately doesn't provide the information needed to get to the
|
||||
// aggregate type. So we have to stick with the FuncDeclaration and
|
||||
// just be sure we don't actually rely on the symbol it points to,
|
||||
// but rather just the type of its context parameter.
|
||||
// this means some function might have a function type pointing to
|
||||
// another function declaration
|
||||
|
||||
if (type)
|
||||
{
|
||||
assert(type->ty == Tfunction && "invalid function type");
|
||||
TypeFunction* tf = (TypeFunction*)type;
|
||||
if (tf->funcdecl == NULL)
|
||||
tf->funcdecl = this;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#if IN_LLVM
|
||||
#include <cmath>
|
||||
#endif
|
||||
|
||||
/* Lexical Analyzer */
|
||||
|
||||
|
||||
72
dmd/mtype.c
72
dmd/mtype.c
@@ -350,14 +350,14 @@ Type *Type::toBasetype()
|
||||
* Name mangling.
|
||||
*/
|
||||
|
||||
void Type::toDecoBuffer(OutBuffer *buf)
|
||||
void Type::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{
|
||||
buf->writeByte(mangleChar[ty]);
|
||||
if (next)
|
||||
{
|
||||
assert(next != this);
|
||||
//printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty);
|
||||
next->toDecoBuffer(buf);
|
||||
next->toDecoBuffer(buf, mangle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ Type *Type::merge()
|
||||
|
||||
if (next)
|
||||
next = next->merge();
|
||||
toDecoBuffer(&buf);
|
||||
toDecoBuffer(&buf, false);
|
||||
sv = stringtable.update((char *)buf.data, buf.offset);
|
||||
if (sv->ptrvalue)
|
||||
{ t = (Type *) sv->ptrvalue;
|
||||
@@ -444,7 +444,11 @@ Type *Type::merge()
|
||||
else
|
||||
{
|
||||
sv->ptrvalue = this;
|
||||
deco = sv->lstring.string;
|
||||
|
||||
OutBuffer mangle;
|
||||
toDecoBuffer(&mangle, true);
|
||||
mangle.writeByte(0);
|
||||
deco = mem.strdup((char *)mangle.data);
|
||||
//printf("new value, deco = '%s' %p\n", t->deco, t->deco);
|
||||
}
|
||||
}
|
||||
@@ -743,7 +747,7 @@ Identifier *Type::getTypeInfoIdent(int internal)
|
||||
buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]);
|
||||
}
|
||||
else
|
||||
toDecoBuffer(&buf);
|
||||
toDecoBuffer(&buf, true);
|
||||
len = buf.offset;
|
||||
name = (char *)alloca(19 + sizeof(len) * 3 + len + 1);
|
||||
buf.writeByte(0);
|
||||
@@ -1933,13 +1937,13 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc)
|
||||
return merge();
|
||||
}
|
||||
|
||||
void TypeSArray::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeSArray::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{
|
||||
buf->writeByte(mangleChar[ty]);
|
||||
if (dim)
|
||||
buf->printf("%ju", dim->toInteger());
|
||||
if (next)
|
||||
next->toDecoBuffer(buf);
|
||||
next->toDecoBuffer(buf, mangle);
|
||||
}
|
||||
|
||||
void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
|
||||
@@ -2099,11 +2103,11 @@ Type *TypeDArray::semantic(Loc loc, Scope *sc)
|
||||
return merge();
|
||||
}
|
||||
|
||||
void TypeDArray::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeDArray::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{
|
||||
buf->writeByte(mangleChar[ty]);
|
||||
if (next)
|
||||
next->toDecoBuffer(buf);
|
||||
next->toDecoBuffer(buf, mangle);
|
||||
}
|
||||
|
||||
void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
|
||||
@@ -2425,11 +2429,11 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
|
||||
return e;
|
||||
}
|
||||
|
||||
void TypeAArray::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeAArray::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{
|
||||
buf->writeByte(mangleChar[ty]);
|
||||
index->toDecoBuffer(buf);
|
||||
next->toDecoBuffer(buf);
|
||||
index->toDecoBuffer(buf, mangle);
|
||||
next->toDecoBuffer(buf, mangle);
|
||||
}
|
||||
|
||||
void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
|
||||
@@ -2651,6 +2655,10 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en
|
||||
this->varargs = varargs;
|
||||
this->linkage = linkage;
|
||||
this->inuse = 0;
|
||||
|
||||
#if IN_LLVM
|
||||
this->funcdecl = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
Type *TypeFunction::syntaxCopy()
|
||||
@@ -2750,7 +2758,7 @@ Lnotcovariant:
|
||||
return 2;
|
||||
}
|
||||
|
||||
void TypeFunction::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeFunction::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{ unsigned char mc;
|
||||
|
||||
//printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars());
|
||||
@@ -2775,11 +2783,23 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf)
|
||||
assert(0);
|
||||
}
|
||||
buf->writeByte(mc);
|
||||
|
||||
// LDC: if we're not producing a mangle string, add the this
|
||||
// type to prevent merging different member function
|
||||
if (!mangle && funcdecl)
|
||||
{
|
||||
if (AggregateDeclaration* ad = funcdecl->isMember())
|
||||
{
|
||||
buf->writeByte('M');
|
||||
ad->type->toDecoBuffer(buf, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Write argument types
|
||||
Argument::argsToDecoBuffer(buf, parameters);
|
||||
Argument::argsToDecoBuffer(buf, parameters, mangle);
|
||||
//if (buf->data[buf->offset - 1] == '@') halt();
|
||||
buf->writeByte('Z' - varargs); // mark end of arg list
|
||||
next->toDecoBuffer(buf);
|
||||
next->toDecoBuffer(buf, mangle);
|
||||
inuse--;
|
||||
}
|
||||
|
||||
@@ -3461,7 +3481,7 @@ Type *TypeIdentifier::syntaxCopy()
|
||||
return t;
|
||||
}
|
||||
|
||||
void TypeIdentifier::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeIdentifier::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{ unsigned len;
|
||||
char *name;
|
||||
|
||||
@@ -3915,7 +3935,7 @@ Type *TypeEnum::toBasetype()
|
||||
return sym->memtype->toBasetype();
|
||||
}
|
||||
|
||||
void TypeEnum::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeEnum::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{ char *name;
|
||||
|
||||
name = sym->mangle();
|
||||
@@ -4103,7 +4123,7 @@ Dsymbol *TypeTypedef::toDsymbol(Scope *sc)
|
||||
return sym;
|
||||
}
|
||||
|
||||
void TypeTypedef::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeTypedef::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{ unsigned len;
|
||||
char *name;
|
||||
|
||||
@@ -4328,7 +4348,7 @@ Dsymbol *TypeStruct::toDsymbol(Scope *sc)
|
||||
return sym;
|
||||
}
|
||||
|
||||
void TypeStruct::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeStruct::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{ unsigned len;
|
||||
char *name;
|
||||
|
||||
@@ -4621,7 +4641,7 @@ Dsymbol *TypeClass::toDsymbol(Scope *sc)
|
||||
return sym;
|
||||
}
|
||||
|
||||
void TypeClass::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeClass::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{ unsigned len;
|
||||
char *name;
|
||||
|
||||
@@ -5143,11 +5163,11 @@ void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
|
||||
Argument::argsToCBuffer(buf, hgs, arguments, 0);
|
||||
}
|
||||
|
||||
void TypeTuple::toDecoBuffer(OutBuffer *buf)
|
||||
void TypeTuple::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{
|
||||
//printf("TypeTuple::toDecoBuffer() this = %p\n", this);
|
||||
OutBuffer buf2;
|
||||
Argument::argsToDecoBuffer(&buf2, arguments);
|
||||
Argument::argsToDecoBuffer(&buf2, arguments, mangle);
|
||||
unsigned len = buf2.offset;
|
||||
buf->printf("%c%d%.*s", mangleChar[ty], len, len, (char *)buf2.extractData());
|
||||
}
|
||||
@@ -5409,7 +5429,7 @@ void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *argume
|
||||
}
|
||||
|
||||
|
||||
void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments)
|
||||
void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangle)
|
||||
{
|
||||
//printf("Argument::argsToDecoBuffer()\n");
|
||||
|
||||
@@ -5420,7 +5440,7 @@ void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments)
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
{
|
||||
Argument *arg = Argument::getNth(arguments, i);
|
||||
arg->toDecoBuffer(buf);
|
||||
arg->toDecoBuffer(buf, mangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5454,7 +5474,7 @@ Type *Argument::isLazyArray()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Argument::toDecoBuffer(OutBuffer *buf)
|
||||
void Argument::toDecoBuffer(OutBuffer *buf, bool mangle)
|
||||
{
|
||||
switch (storageClass & (STCin | STCout | STCref | STClazy))
|
||||
{ case 0:
|
||||
@@ -5475,7 +5495,7 @@ void Argument::toDecoBuffer(OutBuffer *buf)
|
||||
#endif
|
||||
assert(0);
|
||||
}
|
||||
type->toDecoBuffer(buf);
|
||||
type->toDecoBuffer(buf, mangle);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
|
||||
31
dmd/mtype.h
31
dmd/mtype.h
@@ -219,7 +219,8 @@ struct Type : Object
|
||||
virtual d_uns64 size(Loc loc);
|
||||
virtual unsigned alignsize();
|
||||
virtual Type *semantic(Loc loc, Scope *sc);
|
||||
virtual void toDecoBuffer(OutBuffer *buf);
|
||||
// append the mangleof or a string uniquely identifying this type to buf
|
||||
virtual void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
Type *merge();
|
||||
virtual void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
|
||||
virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
@@ -336,7 +337,7 @@ struct TypeSArray : TypeArray
|
||||
unsigned alignsize();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
int isString();
|
||||
@@ -367,7 +368,7 @@ struct TypeDArray : TypeArray
|
||||
d_uns64 size(Loc loc);
|
||||
unsigned alignsize();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
int isString();
|
||||
@@ -394,7 +395,7 @@ struct TypeAArray : TypeArray
|
||||
d_uns64 size(Loc loc);
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
Expression *defaultInit(Loc loc);
|
||||
@@ -462,7 +463,7 @@ struct TypeFunction : Type
|
||||
TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage);
|
||||
Type *syntaxCopy();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
|
||||
@@ -481,6 +482,8 @@ struct TypeFunction : Type
|
||||
#elif IN_LLVM
|
||||
// LDC
|
||||
IrFuncTy fty;
|
||||
|
||||
FuncDeclaration* funcdecl;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -525,7 +528,7 @@ struct TypeIdentifier : TypeQualified
|
||||
TypeIdentifier(Loc loc, Identifier *ident);
|
||||
Type *syntaxCopy();
|
||||
//char *toChars();
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
@@ -544,7 +547,7 @@ struct TypeInstance : TypeQualified
|
||||
TypeInstance(Loc loc, TemplateInstance *tempinst);
|
||||
Type *syntaxCopy();
|
||||
//char *toChars();
|
||||
//void toDecoBuffer(OutBuffer *buf);
|
||||
//void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps);
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
@@ -575,7 +578,7 @@ struct TypeStruct : Type
|
||||
Type *syntaxCopy();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
unsigned memalign(unsigned salign);
|
||||
@@ -610,7 +613,7 @@ struct TypeEnum : Type
|
||||
Type *syntaxCopy();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
Expression *getProperty(Loc loc, Identifier *ident);
|
||||
@@ -642,7 +645,7 @@ struct TypeTypedef : Type
|
||||
char *toChars();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
Expression *getProperty(Loc loc, Identifier *ident);
|
||||
@@ -682,7 +685,7 @@ struct TypeClass : Type
|
||||
Type *syntaxCopy();
|
||||
Type *semantic(Loc loc, Scope *sc);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
|
||||
ClassDeclaration *isClassHandle();
|
||||
@@ -714,7 +717,7 @@ struct TypeTuple : Type
|
||||
int equals(Object *o);
|
||||
Type *reliesOnTident();
|
||||
void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod);
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
Expression *getProperty(Loc loc, Identifier *ident);
|
||||
TypeInfoDeclaration *getTypeInfoDeclaration();
|
||||
};
|
||||
@@ -746,11 +749,11 @@ struct Argument : Object
|
||||
Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg);
|
||||
Argument *syntaxCopy();
|
||||
Type *isLazyArray();
|
||||
void toDecoBuffer(OutBuffer *buf);
|
||||
void toDecoBuffer(OutBuffer *buf, bool mangle);
|
||||
static Arguments *arraySyntaxCopy(Arguments *args);
|
||||
static char *argsTypesToChars(Arguments *args, int varargs);
|
||||
static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs);
|
||||
static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments);
|
||||
static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangle);
|
||||
static size_t dim(Arguments *arguments);
|
||||
static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef LLVMC_GEN_ARRAYS_H
|
||||
#define LLVMC_GEN_ARRAYS_H
|
||||
|
||||
struct ArrayInitializer;
|
||||
|
||||
struct DSliceValue;
|
||||
|
||||
const llvm::StructType* DtoArrayType(Type* arrayTy);
|
||||
|
||||
1018
gen/classes.cpp
1018
gen/classes.cpp
File diff suppressed because it is too large
Load Diff
@@ -3,28 +3,21 @@
|
||||
|
||||
#include "gen/structs.h"
|
||||
|
||||
/**
|
||||
* Resolves the llvm type for a class declaration
|
||||
*/
|
||||
/// Resolves the llvm type for a class declaration
|
||||
void DtoResolveClass(ClassDeclaration* cd);
|
||||
|
||||
/**
|
||||
* Provides the llvm declaration for a class declaration
|
||||
*/
|
||||
/// Provides the llvm declaration for a class declaration
|
||||
void DtoDeclareClass(ClassDeclaration* cd);
|
||||
|
||||
/**
|
||||
* Constructs the constant initializer for a class declaration
|
||||
*/
|
||||
/// Constructs the constant initializer for a class declaration
|
||||
void DtoConstInitClass(ClassDeclaration* cd);
|
||||
|
||||
/**
|
||||
* Provides the llvm definition for a class declaration
|
||||
*/
|
||||
/// Provides the llvm definition for a class declaration
|
||||
void DtoDefineClass(ClassDeclaration* cd);
|
||||
|
||||
void DtoDeclareClassInfo(ClassDeclaration* cd);
|
||||
void DtoDefineClassInfo(ClassDeclaration* cd);
|
||||
/// Builds the initializer of cd's ClassInfo.
|
||||
/// FIXME: this should be put into IrStruct and eventually IrClass.
|
||||
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
|
||||
|
||||
DValue* DtoNewClass(Loc loc, TypeClass* type, NewExp* newexp);
|
||||
void DtoInitClass(TypeClass* tc, LLValue* dst);
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "ir/ir.h"
|
||||
#include "ir/irvar.h"
|
||||
#include "ir/irtype.h"
|
||||
#include "ir/irtypestruct.h"
|
||||
|
||||
/* ================================================================== */
|
||||
|
||||
@@ -72,11 +74,14 @@ void TupleDeclaration::codegen(Ir* p)
|
||||
|
||||
/* ================================================================== */
|
||||
|
||||
// FIXME: this is horrible!!!
|
||||
|
||||
void VarDeclaration::codegen(Ir* p)
|
||||
{
|
||||
Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// just forward aliases
|
||||
if (aliassym)
|
||||
{
|
||||
Logger::println("alias sym");
|
||||
@@ -84,10 +89,11 @@ void VarDeclaration::codegen(Ir* p)
|
||||
return;
|
||||
}
|
||||
|
||||
// output the parent aggregate first
|
||||
if (AggregateDeclaration* ad = isMember())
|
||||
ad->codegen(p);
|
||||
|
||||
// global variable or magic
|
||||
// global variable
|
||||
#if DMDV2
|
||||
// taken from dmd2/structs
|
||||
if (isDataseg() || (storage_class & (STCconst | STCinvariant) && init))
|
||||
@@ -138,25 +144,8 @@ void VarDeclaration::codegen(Ir* p)
|
||||
if (nakedUse)
|
||||
gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType()));
|
||||
|
||||
// don't initialize static struct members yet, they might be of the struct type
|
||||
// which doesn't have a static initializer yet.
|
||||
if (AggregateDeclaration* ad = isMember())
|
||||
ad->ir.irStruct->staticVars.push_back(this);
|
||||
else
|
||||
DtoConstInitGlobal(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// might already have its irField, as classes derive each other without getting copies of the VarDeclaration
|
||||
if (!ir.irField)
|
||||
{
|
||||
assert(!ir.isSet());
|
||||
ir.irField = new IrField(this);
|
||||
}
|
||||
IrStruct* irstruct = gIR->topstruct();
|
||||
irstruct->addVar(this);
|
||||
|
||||
Logger::println("added offset %u", offset);
|
||||
// initialize
|
||||
DtoConstInitGlobal(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +153,7 @@ void VarDeclaration::codegen(Ir* p)
|
||||
|
||||
void TypedefDeclaration::codegen(Ir*)
|
||||
{
|
||||
static int tdi = 0;
|
||||
Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars());
|
||||
Logger::print("TypedefDeclaration::toObjFile: %s\n", toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// generate typeinfo
|
||||
@@ -181,33 +169,12 @@ void EnumDeclaration::codegen(Ir*)
|
||||
|
||||
/* ================================================================== */
|
||||
|
||||
void FuncDeclaration::codegen(Ir*)
|
||||
void FuncDeclaration::codegen(Ir* p)
|
||||
{
|
||||
DtoResolveDsymbol(this);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
|
||||
void AnonDeclaration::codegen(Ir* p)
|
||||
{
|
||||
Array *d = include(NULL, NULL);
|
||||
|
||||
if (d)
|
||||
// don't touch function aliases, they don't contribute any new symbols
|
||||
if (!isFuncAliasDeclaration())
|
||||
{
|
||||
// get real aggregate parent
|
||||
IrStruct* irstruct = gIR->topstruct();
|
||||
|
||||
// push a block on the stack
|
||||
irstruct->pushAnon(isunion);
|
||||
|
||||
// go over children
|
||||
for (unsigned i = 0; i < d->dim; i++)
|
||||
{ Dsymbol *s = (Dsymbol *)d->data[i];
|
||||
s->codegen(p);
|
||||
}
|
||||
|
||||
// finish
|
||||
irstruct->popAnon();
|
||||
DtoResolveDsymbol(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,9 @@ const llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nest
|
||||
llvm::FunctionType* functype = llvm::FunctionType::get(f->fty.ret->ltype, argtypes, f->fty.c_vararg);
|
||||
f->ir.type = new llvm::PATypeHolder(functype);
|
||||
|
||||
#if 0
|
||||
Logger::cout() << "Final function type: " << *functype << "\n";
|
||||
#endif
|
||||
|
||||
return functype;
|
||||
}
|
||||
@@ -304,16 +306,6 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
|
||||
return; // ignore declaration completely
|
||||
}
|
||||
|
||||
if (AggregateDeclaration* ad = fdecl->isMember())
|
||||
{
|
||||
ad->codegen(Type::sir);
|
||||
if (ad->isStructDeclaration() && llvm::isa<llvm::OpaqueType>(DtoType(ad->type)))
|
||||
{
|
||||
ad->ir.irStruct->structFuncs.push_back(fdecl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("resolve function: %s\n", fdecl->toPrettyChars());
|
||||
|
||||
if (fdecl->parent)
|
||||
@@ -372,7 +364,6 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
|
||||
// queue declaration unless the function is abstract without body
|
||||
if (!fdecl->isAbstract() || fdecl->fbody)
|
||||
{
|
||||
Logger::println("Ignoring declaration of abstract bodyless function %s", fdecl->toPrettyChars());
|
||||
DtoDeclareFunction(fdecl);
|
||||
}
|
||||
}
|
||||
@@ -465,6 +456,9 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
Type* t = fdecl->type->toBasetype();
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
|
||||
// sanity check
|
||||
assert(fdecl == f->funcdecl && "the function type does not point to this function");
|
||||
|
||||
bool declareOnly = !mustDefineSymbol(fdecl);
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start)
|
||||
|
||||
@@ -1069,7 +1069,8 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init)
|
||||
else if (StructInitializer* si = init->isStructInitializer())
|
||||
{
|
||||
Logger::println("const struct initializer");
|
||||
_init = DtoConstStructInitializer(si);
|
||||
si->ad->codegen(Type::sir);
|
||||
return si->ad->ir.irStruct->createStructInitializer(si);
|
||||
}
|
||||
else if (ArrayInitializer* ai = init->isArrayInitializer())
|
||||
{
|
||||
|
||||
@@ -33,5 +33,7 @@ namespace Logger
|
||||
|
||||
#define LOG_SCOPE Logger::LoggerScope _logscope;
|
||||
|
||||
#define IF_LOG if (Logger::enabled())
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
619
gen/structs.cpp
619
gen/structs.cpp
@@ -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 @@ LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 @@ void DtoResolveStruct(StructDeclaration* sd)
|
||||
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());
|
||||
// emit the initZ symbol
|
||||
LLGlobalVariable* initZ = irstruct->getInitSymbol();
|
||||
|
||||
// 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;
|
||||
|
||||
// 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++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// emit functions
|
||||
size_t n = irstruct->structFuncs.size();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
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);
|
||||
// perform definition
|
||||
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;
|
||||
// set initZ initializer
|
||||
initZ->setInitializer(irstruct->getDefaultInit());
|
||||
}
|
||||
|
||||
// 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)
|
||||
// emit members
|
||||
if (sd->members)
|
||||
{
|
||||
DtoConstInitGlobal(irstruct->staticVars[i]);
|
||||
ArrayIter<Dsymbol> it(*sd->members);
|
||||
while (!it.done())
|
||||
{
|
||||
Dsymbol* member = it.get();
|
||||
if (member)
|
||||
member->codegen(Type::sir);
|
||||
it.next();
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "gen/logger.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/linkage.h"
|
||||
#include "gen/utils.h"
|
||||
|
||||
#include "ir/irmodule.h"
|
||||
|
||||
@@ -288,14 +289,12 @@ static llvm::DICompositeType dwarfCompositeType(Type* type, llvm::DICompileUnit
|
||||
std::vector<LLConstant*> elems;
|
||||
if (!ir->aggrdecl->isInterfaceDeclaration()) // plain interfaces don't have one
|
||||
{
|
||||
std::vector<VarDeclaration*>& arr = ir->varDecls;
|
||||
size_t narr = arr.size();
|
||||
ArrayIter<VarDeclaration> it(sd->fields);
|
||||
size_t narr = sd->fields.dim;
|
||||
elems.reserve(narr);
|
||||
for (int k=0; k<narr; k++)
|
||||
for (; !it.done(); it.next())
|
||||
{
|
||||
VarDeclaration* vd = arr[k];
|
||||
assert(vd);
|
||||
|
||||
VarDeclaration* vd = it.get();
|
||||
LLGlobalVariable* ptr = dwarfMemberType(vd->loc.linnum, vd->type, compileUnit, definedCU, vd->toChars(), vd->offset).getGV();
|
||||
elems.push_back(DBG_CAST(ptr));
|
||||
}
|
||||
|
||||
26
gen/toir.cpp
26
gen/toir.cpp
@@ -131,8 +131,7 @@ DValue* VarExp::toElem(IRState* p)
|
||||
{
|
||||
Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars());
|
||||
cid->cd->codegen(Type::sir);;
|
||||
assert(cid->cd->ir.irStruct->classInfo);
|
||||
return new DVarValue(type, vd, cid->cd->ir.irStruct->classInfo);
|
||||
return new DVarValue(type, vd, cid->cd->ir.irStruct->getClassInfoSymbol());
|
||||
}
|
||||
// nested variable
|
||||
#if DMDV2
|
||||
@@ -216,8 +215,8 @@ DValue* VarExp::toElem(IRState* p)
|
||||
TypeStruct* ts = (TypeStruct*)sdecltype;
|
||||
assert(ts->sym);
|
||||
ts->sym->codegen(Type::sir);
|
||||
assert(ts->sym->ir.irStruct->init);
|
||||
return new DVarValue(type, ts->sym->ir.irStruct->init);
|
||||
|
||||
return new DVarValue(type, ts->sym->ir.irStruct->getInitSymbol());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -242,8 +241,8 @@ LLConstant* VarExp::toConstElem(IRState* p)
|
||||
assert(sdecltype->ty == Tstruct);
|
||||
TypeStruct* ts = (TypeStruct*)sdecltype;
|
||||
ts->sym->codegen(Type::sir);
|
||||
assert(ts->sym->ir.irStruct->constInit);
|
||||
return ts->sym->ir.irStruct->constInit;
|
||||
|
||||
return ts->sym->ir.irStruct->getDefaultInit();
|
||||
}
|
||||
|
||||
if (TypeInfoDeclaration* ti = var->isTypeInfoDeclaration())
|
||||
@@ -1134,9 +1133,7 @@ DValue* DotVarExp::toElem(IRState* p)
|
||||
size_t vtblidx = fdecl->vtblIndex;
|
||||
if (Logger::enabled())
|
||||
Logger::cout() << "vthis: " << *vthis << '\n';
|
||||
funcval = vthis;
|
||||
if (!fdecl->isMember2()->isInterfaceDeclaration())
|
||||
funcval = DtoGEP(funcval, zero, zero);
|
||||
funcval = DtoGEP(vthis, zero, zero);
|
||||
funcval = DtoLoad(funcval);
|
||||
Logger::println("vtblidx = %lu", vtblidx);
|
||||
funcval = DtoGEP(funcval, zero, DtoConstUint(vtblidx), toChars());
|
||||
@@ -1646,7 +1643,7 @@ DValue* NewExp::toElem(IRState* p)
|
||||
else {
|
||||
assert(ts->sym);
|
||||
ts->sym->codegen(Type::sir);
|
||||
DtoAggrCopy(mem,ts->sym->ir.irStruct->init);
|
||||
DtoAggrCopy(mem,ts->sym->ir.irStruct->getInitSymbol());
|
||||
}
|
||||
return new DImValue(type, mem);
|
||||
}
|
||||
@@ -1658,8 +1655,7 @@ DValue* NewExp::toElem(IRState* p)
|
||||
DVarValue tmpvar(newtype, mem);
|
||||
|
||||
// default initialize
|
||||
// FIXME: should this use DtoConstExpInit instead ?
|
||||
// or is static arrays the only troublemaker?
|
||||
// static arrays never appear here, so using the defaultInit is ok!
|
||||
Expression* exp = newtype->defaultInit(loc);
|
||||
DValue* iv = exp->toElem(gIR);
|
||||
DtoAssign(loc, &tmpvar, iv);
|
||||
@@ -2413,7 +2409,8 @@ DValue* StructLiteralExp::toElem(IRState* p)
|
||||
}
|
||||
|
||||
// vector of values to build aggregate from
|
||||
std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
|
||||
std::vector<LLValue*> values;// = DtoStructLiteralValues(sd, inits);
|
||||
assert(0 && "struct literal exp todo");
|
||||
|
||||
// get the struct type from the values
|
||||
size_t n = values.size();
|
||||
@@ -2462,7 +2459,8 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p)
|
||||
inits[i] = exprs[i]->toConstElem(p);
|
||||
|
||||
// vector of values to build aggregate from
|
||||
std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
|
||||
std::vector<LLValue*> values;// = DtoStructLiteralValues(sd, inits);
|
||||
assert(0 && "struct literal const exp todo");
|
||||
|
||||
// we know those values are constants.. cast them
|
||||
std::vector<LLConstant*> constvals(values.size(), NULL);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "gen/llvm-version.h"
|
||||
|
||||
#include "ir/irtype.h"
|
||||
#include "ir/irtypeclass.h"
|
||||
|
||||
bool DtoIsPassedByRef(Type* type)
|
||||
{
|
||||
@@ -52,11 +53,17 @@ unsigned DtoShouldExtend(Type* type)
|
||||
|
||||
const LLType* DtoType(Type* t)
|
||||
{
|
||||
#if DMDV2
|
||||
t = t->mutableOf();
|
||||
#endif
|
||||
|
||||
if (t->irtype)
|
||||
{
|
||||
return t->irtype->get();
|
||||
}
|
||||
|
||||
IF_LOG Logger::println("Building type: %s", t->toChars());
|
||||
|
||||
assert(t);
|
||||
switch (t->ty)
|
||||
{
|
||||
@@ -86,57 +93,50 @@ const LLType* DtoType(Type* t)
|
||||
case Tdchar:
|
||||
{
|
||||
t->irtype = new IrTypeBasic(t);
|
||||
return t->irtype->get();
|
||||
return t->irtype->buildType();
|
||||
}
|
||||
|
||||
// pointers
|
||||
case Tpointer:
|
||||
{
|
||||
t->irtype = new IrTypePointer(t);
|
||||
return t->irtype->get();
|
||||
return t->irtype->buildType();
|
||||
}
|
||||
|
||||
// arrays
|
||||
case Tarray:
|
||||
{
|
||||
t->irtype = new IrTypeArray(t);
|
||||
return t->irtype->get();
|
||||
return t->irtype->buildType();
|
||||
}
|
||||
|
||||
case Tsarray:
|
||||
{
|
||||
t->irtype = new IrTypeSArray(t);
|
||||
return t->irtype->get();
|
||||
return t->irtype->buildType();
|
||||
}
|
||||
|
||||
// aggregates
|
||||
case Tstruct: {
|
||||
#if DMDV2
|
||||
TypeStruct* ts = (TypeStruct*)t->mutableOf();
|
||||
#else
|
||||
TypeStruct* ts = (TypeStruct*)t;
|
||||
#endif
|
||||
assert(ts->sym);
|
||||
DtoResolveDsymbol(ts->sym);
|
||||
return ts->ir.type->get();
|
||||
t->irtype = new IrTypeStruct(ts->sym);
|
||||
return t->irtype->buildType();
|
||||
}
|
||||
|
||||
case Tclass: {
|
||||
#if DMDV2
|
||||
TypeClass* tc = (TypeClass*)t->mutableOf();
|
||||
#else
|
||||
TypeClass* tc = (TypeClass*)t;
|
||||
#endif
|
||||
assert(tc->sym);
|
||||
DtoResolveDsymbol(tc->sym);
|
||||
return getPtrToType(tc->ir.type->get());
|
||||
t->irtype = new IrTypeClass(tc->sym);
|
||||
return t->irtype->buildType();
|
||||
}
|
||||
|
||||
// functions
|
||||
case Tfunction:
|
||||
{
|
||||
if (!t->ir.type || *t->ir.type == NULL) {
|
||||
return DtoFunctionType(t,NULL,NULL);
|
||||
TypeFunction* tf = (TypeFunction*)t;
|
||||
if (tf->funcdecl)
|
||||
return DtoFunctionType(tf->funcdecl);
|
||||
else
|
||||
return DtoFunctionType(tf,NULL,NULL);
|
||||
}
|
||||
else {
|
||||
return t->ir.type->get();
|
||||
@@ -156,6 +156,8 @@ const LLType* DtoType(Type* t)
|
||||
|
||||
// typedefs
|
||||
// enum
|
||||
|
||||
// FIXME: maybe just call toBasetype first ?
|
||||
case Ttypedef:
|
||||
case Tenum:
|
||||
{
|
||||
@@ -166,15 +168,7 @@ const LLType* DtoType(Type* t)
|
||||
|
||||
// associative arrays
|
||||
case Taarray:
|
||||
#if 1
|
||||
return getVoidPtrType();
|
||||
#else
|
||||
{
|
||||
TypeAArray* taa = (TypeAArray*)t;
|
||||
// aa key/val can't be void
|
||||
return getPtrToType(LLStructType::get(DtoType(taa->key), DtoType(taa->next), 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Not needed atm as VarDecls for tuples are rewritten as a string of
|
||||
|
||||
@@ -146,7 +146,7 @@ llvm::Module* Module::genLLVMModule(Ir* sir)
|
||||
sir->emitFunctionBodies();
|
||||
|
||||
// generate ModuleInfo
|
||||
genmoduleinfo();
|
||||
//genmoduleinfo();
|
||||
|
||||
// emit usedArray
|
||||
if (!ir.usedArray.empty())
|
||||
@@ -621,7 +621,7 @@ void Module::genmoduleinfo()
|
||||
LLConstant* c = 0;
|
||||
|
||||
// vtable
|
||||
c = moduleinfo->ir.irStruct->vtbl;
|
||||
c = moduleinfo->ir.irStruct->getVtblSymbol();
|
||||
initVec.push_back(c);
|
||||
|
||||
// monitor
|
||||
@@ -696,8 +696,7 @@ void Module::genmoduleinfo()
|
||||
continue;
|
||||
}
|
||||
Logger::println("class: %s", cd->toPrettyChars());
|
||||
assert(cd->ir.irStruct->classInfo);
|
||||
c = DtoBitCast(cd->ir.irStruct->classInfo, getPtrToType(classinfoTy));
|
||||
c = DtoBitCast(cd->ir.irStruct->getClassInfoSymbol(), getPtrToType(classinfoTy));
|
||||
classInits.push_back(c);
|
||||
}
|
||||
// has class array?
|
||||
|
||||
@@ -253,20 +253,6 @@ int TypeDArray::builtinTypeInfo()
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
/***************************************
|
||||
* 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); // done elsewhere in LDC
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// MAGIC PLACE
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -376,7 +362,7 @@ void TypeInfoTypedefDeclaration::llvmDefine()
|
||||
|
||||
// vtbl
|
||||
std::vector<LLConstant*> sinits;
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(getNullPtr(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -433,7 +419,7 @@ void TypeInfoEnumDeclaration::llvmDefine()
|
||||
|
||||
// vtbl
|
||||
std::vector<LLConstant*> sinits;
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -491,7 +477,7 @@ static void LLVM_D_Define_TypeInfoBase(Type* basetype, TypeInfoDeclaration* tid,
|
||||
|
||||
// vtbl
|
||||
std::vector<LLConstant*> sinits;
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -553,7 +539,7 @@ void TypeInfoStaticArrayDeclaration::llvmDefine()
|
||||
// initializer vector
|
||||
std::vector<LLConstant*> sinits;
|
||||
// first is always the vtable
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -592,7 +578,7 @@ void TypeInfoAssociativeArrayDeclaration::llvmDefine()
|
||||
// initializer vector
|
||||
std::vector<LLConstant*> sinits;
|
||||
// first is always the vtable
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -664,7 +650,7 @@ void TypeInfoStructDeclaration::llvmDefine()
|
||||
|
||||
// vtbl
|
||||
std::vector<LLConstant*> sinits;
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -687,7 +673,7 @@ void TypeInfoStructDeclaration::llvmDefine()
|
||||
#endif
|
||||
{
|
||||
size_t cisize = getTypeStoreSize(tc->ir.type->get());
|
||||
LLConstant* cicast = llvm::ConstantExpr::getBitCast(sd->ir.irStruct->init, initpt);
|
||||
LLConstant* cicast = llvm::ConstantExpr::getBitCast(sd->ir.irStruct->getInitSymbol(), initpt);
|
||||
sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast));
|
||||
}
|
||||
|
||||
@@ -857,7 +843,7 @@ void TypeInfoClassDeclaration::llvmDefine()
|
||||
// initializer vector
|
||||
std::vector<LLConstant*> sinits;
|
||||
// first is always the vtable
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -865,9 +851,10 @@ void TypeInfoClassDeclaration::llvmDefine()
|
||||
// get classinfo
|
||||
assert(tinfo->ty == Tclass);
|
||||
TypeClass *tc = (TypeClass *)tinfo;
|
||||
tc->sym->codegen(Type::sir);;
|
||||
assert(tc->sym->ir.irStruct->classInfo);
|
||||
sinits.push_back(tc->sym->ir.irStruct->classInfo);
|
||||
|
||||
tc->sym->codegen(Type::sir);
|
||||
|
||||
sinits.push_back(tc->sym->ir.irStruct->getClassInfoSymbol());
|
||||
|
||||
// create the inititalizer
|
||||
LLConstant* tiInit = llvm::ConstantStruct::get(sinits);
|
||||
@@ -897,7 +884,7 @@ void TypeInfoInterfaceDeclaration::llvmDefine()
|
||||
// initializer vector
|
||||
std::vector<LLConstant*> sinits;
|
||||
// first is always the vtable
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
@@ -905,8 +892,8 @@ void TypeInfoInterfaceDeclaration::llvmDefine()
|
||||
// get classinfo
|
||||
assert(tinfo->ty == Tclass);
|
||||
TypeClass *tc = (TypeClass *)tinfo;
|
||||
assert(tc->sym->ir.irStruct->classInfo);
|
||||
sinits.push_back(tc->sym->ir.irStruct->classInfo);
|
||||
|
||||
sinits.push_back(tc->sym->ir.irStruct->getClassInfoSymbol());
|
||||
|
||||
// create the inititalizer
|
||||
LLConstant* tiInit = llvm::ConstantStruct::get(sinits);
|
||||
@@ -936,7 +923,7 @@ void TypeInfoTupleDeclaration::llvmDefine()
|
||||
// initializer vector
|
||||
std::vector<LLConstant*> sinits;
|
||||
// first is always the vtable
|
||||
sinits.push_back(base->ir.irStruct->vtbl);
|
||||
sinits.push_back(base->ir.irStruct->getVtblSymbol());
|
||||
|
||||
// monitor
|
||||
sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)));
|
||||
|
||||
46
gen/utils.h
Normal file
46
gen/utils.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef __LDC_GEN_UTILS_H__
|
||||
#define __LDC_GEN_UTILS_H__
|
||||
|
||||
#include "root.h"
|
||||
|
||||
/// Very simple templated iterator for DMD ArrayS.
|
||||
template<class C>
|
||||
struct ArrayIter
|
||||
{
|
||||
Array& array;
|
||||
size_t index;
|
||||
|
||||
ArrayIter(Array& arr, size_t idx = 0)
|
||||
: array(arr), index(idx)
|
||||
{ }
|
||||
|
||||
bool done()
|
||||
{
|
||||
return index >= array.dim;
|
||||
}
|
||||
bool more()
|
||||
{
|
||||
return index < array.dim;
|
||||
}
|
||||
|
||||
C* get()
|
||||
{
|
||||
return static_cast<C*>(array.data[index]);
|
||||
}
|
||||
C* operator->()
|
||||
{
|
||||
return static_cast<C*>(array.data[index]);
|
||||
}
|
||||
|
||||
void next()
|
||||
{
|
||||
++index;
|
||||
}
|
||||
};
|
||||
|
||||
// some aliases
|
||||
typedef ArrayIter<Dsymbol> DsymbolIter;
|
||||
typedef ArrayIter<FuncDeclaration> FuncDeclarationIter;
|
||||
typedef ArrayIter<VarDeclaration> VarDeclarationIter;
|
||||
|
||||
#endif
|
||||
441
ir/irclass.cpp
Normal file
441
ir/irclass.cpp
Normal file
@@ -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));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -128,7 +128,7 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
|
||||
}
|
||||
assert(it->catchType);
|
||||
assert(it->catchType->ir.irStruct);
|
||||
selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->classInfo);
|
||||
selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->getClassInfoSymbol());
|
||||
}
|
||||
}
|
||||
// if there's a finally, the eh table has to have a 0 action
|
||||
|
||||
523
ir/irstruct.cpp
523
ir/irstruct.cpp
@@ -5,353 +5,330 @@
|
||||
#include "declaration.h"
|
||||
#include "init.h"
|
||||
|
||||
#include "ir/irstruct.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/utils.h"
|
||||
|
||||
IrInterface::IrInterface(BaseClass* b)
|
||||
: vtblInitTy(llvm::OpaqueType::get())
|
||||
{
|
||||
base = b;
|
||||
decl = b->base;
|
||||
vtblInit = NULL;
|
||||
vtbl = NULL;
|
||||
infoTy = NULL;
|
||||
infoInit = NULL;
|
||||
info = NULL;
|
||||
#include "ir/irstruct.h"
|
||||
#include "ir/irtypeclass.h"
|
||||
|
||||
index = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrStruct::IrStruct(AggregateDeclaration* aggr)
|
||||
: initOpaque(llvm::OpaqueType::get()),
|
||||
classInfoOpaque(llvm::OpaqueType::get()),
|
||||
vtblTy(llvm::OpaqueType::get()),
|
||||
vtblInitTy(llvm::OpaqueType::get()),
|
||||
diCompositeType(NULL)
|
||||
: diCompositeType(NULL)
|
||||
{
|
||||
aggrdecl = aggr;
|
||||
defaultFound = false;
|
||||
anon = NULL;
|
||||
index = 0;
|
||||
|
||||
type = aggr->type;
|
||||
defined = false;
|
||||
constinited = false;
|
||||
|
||||
interfaceInfos = NULL;
|
||||
vtbl = NULL;
|
||||
constVtbl = NULL;
|
||||
packed = false;
|
||||
|
||||
// above still need to be looked at
|
||||
|
||||
init = NULL;
|
||||
constInit = NULL;
|
||||
|
||||
vtbl = NULL;
|
||||
constVtbl = NULL;
|
||||
classInfo = NULL;
|
||||
constClassInfo = NULL;
|
||||
classInfoDeclared = false;
|
||||
classInfoDefined = false;
|
||||
|
||||
packed = false;
|
||||
classInterfacesArray = NULL;
|
||||
}
|
||||
|
||||
IrStruct::~IrStruct()
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLGlobalVariable * IrStruct::getInitSymbol()
|
||||
{
|
||||
if (init)
|
||||
return init;
|
||||
|
||||
// create the initZ symbol
|
||||
std::string initname("_D");
|
||||
initname.append(aggrdecl->mangle());
|
||||
initname.append("6__initZ");
|
||||
|
||||
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
|
||||
|
||||
init = new llvm::GlobalVariable(
|
||||
type->irtype->getPA().get(), true, _linkage, NULL, initname, gIR->module);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IrStruct::pushAnon(bool isunion)
|
||||
llvm::Constant * IrStruct::getDefaultInit()
|
||||
{
|
||||
anon = new Anon(isunion, anon);
|
||||
}
|
||||
if (constInit)
|
||||
return constInit;
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
void IrStruct::popAnon()
|
||||
{
|
||||
assert(anon);
|
||||
|
||||
const LLType* BT;
|
||||
|
||||
// get the anon type
|
||||
if (anon->isunion)
|
||||
if (type->ty == Tstruct)
|
||||
{
|
||||
// get biggest type in block
|
||||
const LLType* biggest = getBiggestType(&anon->types[0], anon->types.size());
|
||||
std::vector<const LLType*> vec(1, biggest);
|
||||
BT = LLStructType::get(vec, aggrdecl->ir.irStruct->packed);
|
||||
constInit = createStructDefaultInitializer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// build a struct from the types
|
||||
BT = LLStructType::get(anon->types, aggrdecl->ir.irStruct->packed);
|
||||
constInit = createClassDefaultInitializer();
|
||||
}
|
||||
|
||||
// pop anon
|
||||
Anon* tmp = anon;
|
||||
anon = anon->parent;
|
||||
delete tmp;
|
||||
return constInit;
|
||||
}
|
||||
|
||||
// is there a parent anon?
|
||||
if (anon)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// helper function that returns the static default initializer of a variable
|
||||
LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init)
|
||||
{
|
||||
if (init)
|
||||
{
|
||||
// make sure type gets pushed in the anon, not the main
|
||||
anon->types.push_back(BT);
|
||||
// index is only manipulated at the top level, anons use raw offsets
|
||||
return DtoConstInitializer(init->loc, vd->type, init);
|
||||
}
|
||||
else if (vd->init)
|
||||
{
|
||||
return DtoConstInitializer(vd->init->loc, vd->type, vd->init);
|
||||
}
|
||||
// no parent anon, finally add to aggrdecl
|
||||
else
|
||||
{
|
||||
types.push_back(BT);
|
||||
// only advance to next position if main is not a union
|
||||
if (!aggrdecl->isUnionDeclaration())
|
||||
return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc));
|
||||
}
|
||||
}
|
||||
|
||||
// helper function that adds zero bytes to a vector of constants
|
||||
size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff)
|
||||
{
|
||||
size_t n = constants.size();
|
||||
while (diff)
|
||||
{
|
||||
if (global.params.is64bit && diff % 8 == 0)
|
||||
{
|
||||
index++;
|
||||
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int64Ty));
|
||||
diff -= 8;
|
||||
}
|
||||
else if (diff % 4 == 0)
|
||||
{
|
||||
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty));
|
||||
diff -= 4;
|
||||
}
|
||||
else if (diff % 2 == 0)
|
||||
{
|
||||
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int16Ty));
|
||||
diff -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty));
|
||||
diff -= 1;
|
||||
}
|
||||
}
|
||||
return constants.size() - n;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Matches the way the type is built in IrTypeStruct
|
||||
// maybe look at unifying the interface.
|
||||
|
||||
void IrStruct::addVar(VarDeclaration * var)
|
||||
LLConstant * IrStruct::createStructDefaultInitializer()
|
||||
{
|
||||
TypeVector* tvec = &types;
|
||||
if (anon)
|
||||
IF_LOG Logger::println("Building default initializer for %s", aggrdecl->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
assert(type->ty == Tstruct && "cannot build struct default initializer for non struct type");
|
||||
|
||||
// start at offset zero
|
||||
size_t offset = 0;
|
||||
|
||||
// vector of constants
|
||||
std::vector<llvm::Constant*> constants;
|
||||
|
||||
// go through fields
|
||||
ArrayIter<VarDeclaration> it(aggrdecl->fields);
|
||||
for (; !it.done(); it.next())
|
||||
{
|
||||
// make sure type gets pushed in the anon, not the main
|
||||
tvec = &anon->types;
|
||||
VarDeclaration* vd = it.get();
|
||||
|
||||
// set but don't advance index
|
||||
var->ir.irField->index = index;
|
||||
|
||||
// set offset in bytes from start of anon block
|
||||
var->ir.irField->unionOffset = var->offset - var->offset2;
|
||||
}
|
||||
else if (aggrdecl->isUnionDeclaration())
|
||||
{
|
||||
// set but don't advance index
|
||||
var->ir.irField->index = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set and advance index
|
||||
var->ir.irField->index = index++;
|
||||
}
|
||||
|
||||
// add type
|
||||
tvec->push_back(DtoType(var->type));
|
||||
|
||||
// add var
|
||||
varDecls.push_back(var);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
const LLType* IrStruct::build()
|
||||
{
|
||||
// if types is empty, add a byte
|
||||
if (types.empty())
|
||||
{
|
||||
types.push_back(LLType::Int8Ty);
|
||||
}
|
||||
|
||||
// union type
|
||||
if (aggrdecl->isUnionDeclaration())
|
||||
{
|
||||
const LLType* biggest = getBiggestType(&types[0], types.size());
|
||||
std::vector<const LLType*> vec(1, biggest);
|
||||
return LLStructType::get(vec, aggrdecl->ir.irStruct->packed);
|
||||
}
|
||||
// struct/class type
|
||||
else
|
||||
{
|
||||
return LLStructType::get(types, aggrdecl->ir.irStruct->packed);
|
||||
}
|
||||
}
|
||||
|
||||
void addZeros(std::vector<const llvm::Type*>& inits, size_t pos, size_t offset)
|
||||
{
|
||||
assert(offset > pos);
|
||||
size_t diff = offset - pos;
|
||||
|
||||
size_t sz;
|
||||
|
||||
do
|
||||
{
|
||||
if (pos%8 == 0 && diff >= 8)
|
||||
sz = 8;
|
||||
else if (pos%4 == 0 && diff >= 4)
|
||||
sz = 4;
|
||||
else if (pos%2 == 0 && diff >= 2)
|
||||
sz = 2;
|
||||
else // if (pos % 1 == 0)
|
||||
sz = 1;
|
||||
inits.push_back(LLIntegerType::get(sz*8));
|
||||
pos += sz;
|
||||
diff -= sz;
|
||||
} while (pos < offset);
|
||||
|
||||
assert(pos == offset);
|
||||
}
|
||||
|
||||
void addZeros(std::vector<llvm::Constant*>& inits, size_t pos, size_t offset)
|
||||
{
|
||||
assert(offset > pos);
|
||||
size_t diff = offset - pos;
|
||||
|
||||
size_t sz;
|
||||
|
||||
do
|
||||
{
|
||||
if (pos%8 == 0 && diff >= 8)
|
||||
sz = 8;
|
||||
else if (pos%4 == 0 && diff >= 4)
|
||||
sz = 4;
|
||||
else if (pos%2 == 0 && diff >= 2)
|
||||
sz = 2;
|
||||
else // if (pos % 1 == 0)
|
||||
sz = 1;
|
||||
inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8)));
|
||||
pos += sz;
|
||||
diff -= sz;
|
||||
} while (pos < offset);
|
||||
|
||||
assert(pos == offset);
|
||||
}
|
||||
|
||||
// FIXME: body is exact copy of above
|
||||
void addZeros(std::vector<llvm::Value*>& inits, size_t pos, size_t offset)
|
||||
{
|
||||
assert(offset > pos);
|
||||
size_t diff = offset - pos;
|
||||
|
||||
size_t sz;
|
||||
|
||||
do
|
||||
{
|
||||
if (pos%8 == 0 && diff >= 8)
|
||||
sz = 8;
|
||||
else if (pos%4 == 0 && diff >= 4)
|
||||
sz = 4;
|
||||
else if (pos%2 == 0 && diff >= 2)
|
||||
sz = 2;
|
||||
else // if (pos % 1 == 0)
|
||||
sz = 1;
|
||||
inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8)));
|
||||
pos += sz;
|
||||
diff -= sz;
|
||||
} while (pos < offset);
|
||||
|
||||
assert(pos == offset);
|
||||
}
|
||||
|
||||
void IrStruct::buildDefaultConstInit(std::vector<llvm::Constant*>& inits)
|
||||
{
|
||||
assert(!defaultFound);
|
||||
defaultFound = true;
|
||||
|
||||
const llvm::StructType* structtype = isaStruct(aggrdecl->type->ir.type->get());
|
||||
Logger::cout() << "struct type: " << *structtype << '\n';
|
||||
|
||||
size_t lastoffset = 0;
|
||||
size_t lastsize = 0;
|
||||
|
||||
{
|
||||
Logger::println("Find the default fields");
|
||||
LOG_SCOPE;
|
||||
|
||||
// go through all vars and find the ones that contribute to the default
|
||||
size_t nvars = varDecls.size();
|
||||
for (size_t i=0; i<nvars; i++)
|
||||
if (vd->offset < offset)
|
||||
{
|
||||
VarDeclaration* var = varDecls[i];
|
||||
IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset);
|
||||
IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
|
||||
|
||||
// only add vars that don't overlap
|
||||
size_t offset = var->offset;
|
||||
size_t size = var->type->size();
|
||||
if (offset >= lastoffset+lastsize)
|
||||
// get next aligned offset for this field
|
||||
size_t alignedoffset = offset;
|
||||
if (!packed)
|
||||
{
|
||||
size_t alignsize = vd->type->alignsize();
|
||||
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
|
||||
}
|
||||
|
||||
// insert explicit padding?
|
||||
if (alignedoffset < vd->offset)
|
||||
{
|
||||
add_zeros(constants, vd->offset - alignedoffset);
|
||||
}
|
||||
|
||||
// add initializer
|
||||
constants.push_back(get_default_initializer(vd, NULL));
|
||||
|
||||
// advance offset to right past this field
|
||||
offset = vd->offset + vd->type->size();
|
||||
}
|
||||
|
||||
// tail padding?
|
||||
if (offset < aggrdecl->structsize)
|
||||
{
|
||||
add_zeros(constants, aggrdecl->structsize - offset);
|
||||
}
|
||||
|
||||
// build constant struct
|
||||
llvm::Constant* definit = llvm::ConstantStruct::get(constants, packed);
|
||||
IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl;
|
||||
|
||||
// sanity check
|
||||
assert(definit->getType() == type->irtype->get() &&
|
||||
"default initializer type does not match the default struct type");
|
||||
|
||||
return definit;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// yet another rewrite of the notorious StructInitializer.
|
||||
|
||||
// this time a bit more inspired by the DMD code.
|
||||
|
||||
LLConstant * IrStruct::createStructInitializer(StructInitializer * si)
|
||||
{
|
||||
IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// sanity check
|
||||
assert(si->ad == aggrdecl && "struct type mismatch");
|
||||
assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer");
|
||||
|
||||
// array of things to build
|
||||
typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair;
|
||||
llvm::SmallVector<VCPair, 16> data(aggrdecl->fields.dim);
|
||||
|
||||
// start by creating a map from initializer indices to field indices.
|
||||
// I have no fucking clue why dmd represents it like this :/
|
||||
size_t n = si->vars.dim;
|
||||
LLSmallVector<int, 16> datamap(n, 0);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
for (size_t j = 0; 1; j++)
|
||||
{
|
||||
assert(j < aggrdecl->fields.dim);
|
||||
if (aggrdecl->fields.data[j] == si->vars.data[i])
|
||||
{
|
||||
Logger::println(" added");
|
||||
lastoffset = offset;
|
||||
lastsize = size;
|
||||
defVars.push_back(var);
|
||||
datamap[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill in explicit initializers
|
||||
n = si->vars.dim;
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
Logger::println("Build the default initializer");
|
||||
LOG_SCOPE;
|
||||
VarDeclaration* vd = (VarDeclaration*)si->vars.data[i];
|
||||
Initializer* ini = (Initializer*)si->value.data[i];
|
||||
|
||||
lastoffset = 0;
|
||||
lastsize = 0;
|
||||
size_t idx = datamap[i];
|
||||
|
||||
// go through the default vars and build the default constant initializer
|
||||
// adding zeros along the way to live up to alignment expectations
|
||||
size_t nvars = defVars.size();
|
||||
for (size_t i=0; i<nvars; i++)
|
||||
if (data[idx].first != NULL)
|
||||
{
|
||||
VarDeclaration* var = defVars[i];
|
||||
Loc l = ini ? ini->loc : si->loc;
|
||||
error(l, "duplicate initialization of %s", vd->toChars());
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset);
|
||||
data[idx].first = vd;
|
||||
data[idx].second = get_default_initializer(vd, ini);
|
||||
}
|
||||
|
||||
// get offset and size
|
||||
size_t offset = var->offset;
|
||||
size_t size = var->type->size();
|
||||
// build array of constants and try to fill in default initializers
|
||||
// where there is room.
|
||||
size_t offset = 0;
|
||||
std::vector<llvm::Constant*> constants;
|
||||
constants.reserve(16);
|
||||
|
||||
// is there space in between last last offset and this one?
|
||||
// if so, fill it with zeros
|
||||
if (offset > lastoffset+lastsize)
|
||||
n = data.size();
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
VarDeclaration* vd = data[i].first;
|
||||
|
||||
// explicitly initialized?
|
||||
if (vd != NULL)
|
||||
{
|
||||
// get next aligned offset for this field
|
||||
size_t alignedoffset = offset;
|
||||
if (!packed)
|
||||
{
|
||||
size_t pos = lastoffset + lastsize;
|
||||
addZeros(inits, pos, offset);
|
||||
size_t alignsize = vd->type->alignsize();
|
||||
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
|
||||
}
|
||||
|
||||
// add the field
|
||||
// lazily default initialize
|
||||
if (!var->ir.irField->constInit)
|
||||
var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init);
|
||||
inits.push_back(var->ir.irField->constInit);
|
||||
// insert explicit padding?
|
||||
if (alignedoffset < vd->offset)
|
||||
{
|
||||
add_zeros(constants, vd->offset - alignedoffset);
|
||||
}
|
||||
|
||||
lastoffset = offset;
|
||||
lastsize = var->type->size();
|
||||
IF_LOG Logger::println("using field: %s", vd->toChars());
|
||||
constants.push_back(data[i].second);
|
||||
offset = vd->offset + vd->type->size();
|
||||
}
|
||||
|
||||
// there might still be padding after the last one, make sure that is zeroed as well
|
||||
// is there space in between last last offset and this one?
|
||||
size_t structsize = getTypePaddedSize(structtype);
|
||||
|
||||
if (structsize > lastoffset+lastsize)
|
||||
// not explicit! try and fit in the default initialization instead
|
||||
// make sure we don't overlap with any following explicity initialized fields
|
||||
else
|
||||
{
|
||||
size_t pos = lastoffset + lastsize;
|
||||
addZeros(inits, pos, structsize);
|
||||
vd = (VarDeclaration*)aggrdecl->fields.data[i];
|
||||
|
||||
// check all the way that we don't overlap, slow but it works!
|
||||
for (size_t j = i+1; j <= n; j++)
|
||||
{
|
||||
if (j == n) // no overlap
|
||||
{
|
||||
IF_LOG Logger::println("using field default: %s", vd->toChars());
|
||||
constants.push_back(get_default_initializer(vd, NULL));
|
||||
offset = vd->offset + vd->type->size();
|
||||
break;
|
||||
}
|
||||
|
||||
VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j];
|
||||
|
||||
size_t o2 = vd->offset + vd->type->size();
|
||||
|
||||
if (vd2->offset < o2 && data[i].first)
|
||||
break; // overlaps
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLConstant* IrStruct::buildDefaultConstInit()
|
||||
{
|
||||
// doesn't work for classes, they add stuff before and maybe after data fields
|
||||
assert(!aggrdecl->isClassDeclaration());
|
||||
// tail padding?
|
||||
if (offset < aggrdecl->structsize)
|
||||
{
|
||||
add_zeros(constants, aggrdecl->structsize - offset);
|
||||
}
|
||||
|
||||
// initializer llvm constant list
|
||||
std::vector<LLConstant*> inits;
|
||||
// stop if there were errors
|
||||
if (global.errors)
|
||||
{
|
||||
fatal();
|
||||
}
|
||||
|
||||
// just start with an empty list
|
||||
buildDefaultConstInit(inits);
|
||||
|
||||
// build the constant
|
||||
// note that the type matches the initializer, not the aggregate in cases with unions
|
||||
LLConstant* c = LLConstantStruct::get(inits, aggrdecl->ir.irStruct->packed);
|
||||
Logger::cout() << "llvm constant: " << *c << '\n';
|
||||
// assert(0);
|
||||
// build constant
|
||||
assert(!constants.empty());
|
||||
llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed);
|
||||
IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
236
ir/irstruct.h
236
ir/irstruct.h
@@ -6,178 +6,110 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
struct IrInterface;
|
||||
// DMD forward declarations
|
||||
struct StructInitializer;
|
||||
|
||||
void addZeros(std::vector<const llvm::Type*>& inits, size_t pos, size_t offset);
|
||||
void addZeros(std::vector<llvm::Constant*>& inits, size_t pos, size_t offset);
|
||||
void addZeros(std::vector<llvm::Value*>& inits, size_t pos, size_t offset);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// represents a struct or class
|
||||
// it is used during codegen to hold all the vital info we need
|
||||
struct IrStruct : IrBase
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef std::vector<VarDeclaration*> VarDeclVector;
|
||||
|
||||
typedef std::map<ClassDeclaration*, IrInterface*> InterfaceMap;
|
||||
typedef InterfaceMap::iterator InterfaceMapIter;
|
||||
|
||||
typedef std::vector<IrInterface*> InterfaceVector;
|
||||
typedef InterfaceVector::iterator InterfaceVectorIter;
|
||||
|
||||
// vector of LLVM types
|
||||
typedef std::vector<const llvm::Type*> TypeVector;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Anon represents an anonymous struct union block inside an aggregate
|
||||
// during LLVM type construction.
|
||||
struct Anon
|
||||
{
|
||||
bool isunion;
|
||||
Anon* parent;
|
||||
|
||||
TypeVector types;
|
||||
|
||||
Anon(bool IsUnion, Anon* par) : isunion(IsUnion), parent(par) {}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// ctor
|
||||
/// Constructor.
|
||||
IrStruct(AggregateDeclaration* agg);
|
||||
|
||||
/// dtor
|
||||
virtual ~IrStruct();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// public fields,
|
||||
// FIXME this is basically stuff I just haven't gotten around to yet.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// push an anonymous struct/union
|
||||
void pushAnon(bool isunion);
|
||||
|
||||
/// pops an anonymous struct/union
|
||||
void popAnon();
|
||||
|
||||
/// adds field
|
||||
void addVar(VarDeclaration* var);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// build the aggr type
|
||||
const LLType* build();
|
||||
|
||||
/// put the aggr initializers in a vector
|
||||
void buildDefaultConstInit(std::vector<llvm::Constant*>& inits);
|
||||
|
||||
/// ditto - but also builds the constant struct, for convenience
|
||||
LLConstant* buildDefaultConstInit();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
// the D aggregate
|
||||
/// The D aggregate.
|
||||
AggregateDeclaration* aggrdecl;
|
||||
|
||||
// vector of VarDeclarations in this aggregate
|
||||
VarDeclVector varDecls;
|
||||
|
||||
// vector of VarDeclarations that contribute to the default initializer
|
||||
VarDeclVector defVars;
|
||||
|
||||
// true if the default initializer has been built
|
||||
bool defaultFound;
|
||||
|
||||
// top element
|
||||
Anon* anon;
|
||||
|
||||
// toplevel types in this aggr
|
||||
TypeVector types;
|
||||
|
||||
// current index
|
||||
// always the same as types.size()
|
||||
size_t index;
|
||||
|
||||
// aggregate D type
|
||||
/// Aggregate D type.
|
||||
Type* type;
|
||||
|
||||
// class vtable type
|
||||
llvm::PATypeHolder vtblTy;
|
||||
llvm::PATypeHolder vtblInitTy;
|
||||
|
||||
// initializer type opaque (type of global matches initializer, not formal type)
|
||||
llvm::PATypeHolder initOpaque;
|
||||
llvm::PATypeHolder classInfoOpaque;
|
||||
|
||||
// map/vector of interfaces implemented
|
||||
InterfaceMap interfaceMap;
|
||||
InterfaceVector interfaceVec;
|
||||
|
||||
// interface info array global
|
||||
LLGlobalVariable* interfaceInfos;
|
||||
|
||||
// ...
|
||||
bool defined;
|
||||
bool constinited;
|
||||
|
||||
// vtbl global and initializer
|
||||
LLGlobalVariable* vtbl;
|
||||
LLConstant* constVtbl;
|
||||
|
||||
// static initializers global and constant
|
||||
LLGlobalVariable* init;
|
||||
LLConstant* constInit;
|
||||
|
||||
// classinfo global and initializer constant
|
||||
LLGlobalVariable* classInfo;
|
||||
LLConstant* constClassInfo;
|
||||
bool classInfoDeclared;
|
||||
bool classInfoDefined;
|
||||
// vector of interfaces that should be put in ClassInfo.interfaces
|
||||
InterfaceVector classInfoInterfaces;
|
||||
|
||||
// align(1) struct S { ... }
|
||||
/// true only for: align(1) struct S { ... }
|
||||
bool packed;
|
||||
|
||||
// composite type debug description
|
||||
/// Composite type debug description.
|
||||
llvm::DICompositeType diCompositeType;
|
||||
|
||||
std::vector<VarDeclaration*> staticVars;
|
||||
std::vector<FuncDeclaration*> structFuncs;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Create the __initZ symbol lazily.
|
||||
LLGlobalVariable* getInitSymbol();
|
||||
/// Builds the __initZ initializer constant lazily.
|
||||
LLConstant* getDefaultInit();
|
||||
|
||||
/// Create the __vtblZ symbol lazily.
|
||||
LLGlobalVariable* getVtblSymbol();
|
||||
/// Builds the __vtblZ initializer constant lazily.
|
||||
LLConstant* getVtblInit();
|
||||
|
||||
/// Create the __ClassZ symbol lazily.
|
||||
LLGlobalVariable* getClassInfoSymbol();
|
||||
/// Builds the __ClassZ initializer constant lazily.
|
||||
LLConstant* getClassInfoInit();
|
||||
|
||||
/// Create the __interfaceInfos symbol lazily.
|
||||
LLGlobalVariable* getInterfaceArraySymbol();
|
||||
|
||||
/// Creates a StructInitializer constant.
|
||||
LLConstant* createStructInitializer(StructInitializer* si);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
protected:
|
||||
/// Static default initializer global.
|
||||
llvm::GlobalVariable* init;
|
||||
/// Static default initializer constant.
|
||||
LLConstant* constInit;
|
||||
|
||||
/// Vtbl global.
|
||||
llvm::GlobalVariable* vtbl;
|
||||
/// Vtbl initializer constant.
|
||||
LLConstant* constVtbl;
|
||||
|
||||
/// ClassInfo global.
|
||||
llvm::GlobalVariable* classInfo;
|
||||
/// ClassInfo initializer constant.
|
||||
LLConstant* constClassInfo;
|
||||
|
||||
/// Map for mapping ClassDeclaration* to LLVM GlobalVariable.
|
||||
typedef std::map<ClassDeclaration*, llvm::GlobalVariable*> ClassGlobalMap;
|
||||
|
||||
/// Map from of interface vtbls implemented by this class.
|
||||
ClassGlobalMap interfaceVtblMap;
|
||||
|
||||
/// Interface info array global.
|
||||
/// Basically: static object.Interface[num_interfaces]
|
||||
llvm::GlobalVariable* classInterfacesArray;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Create static default initializer for struct.
|
||||
LLConstant* createStructDefaultInitializer();
|
||||
|
||||
/// Create static default initializer for class.
|
||||
LLConstant* createClassDefaultInitializer();
|
||||
|
||||
/// Returns vtbl for interface implementation, creates it if not already built.
|
||||
llvm::GlobalVariable* getInterfaceVtbl(BaseClass* b, bool new_inst);
|
||||
|
||||
/// Add base class data to initializer list.
|
||||
/// Also creates the IrField instance for each data field.
|
||||
void addBaseClassInits(
|
||||
std::vector<llvm::Constant*>& constants,
|
||||
ClassDeclaration* base,
|
||||
size_t& offset,
|
||||
size_t& field_index);
|
||||
|
||||
// FIXME make this a member instead
|
||||
friend LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
|
||||
|
||||
/// Create the Interface[] interfaces ClassInfo field initializer.
|
||||
LLConstant* getClassInfoInterfaces();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// represents interface implemented by a class
|
||||
struct IrInterface : IrBase
|
||||
{
|
||||
BaseClass* base;
|
||||
ClassDeclaration* decl;
|
||||
|
||||
llvm::PATypeHolder vtblInitTy;
|
||||
|
||||
LLConstant* vtblInit;
|
||||
LLGlobalVariable* vtbl;
|
||||
Array vtblDecls; // array of FuncDecls that make up the vtbl
|
||||
|
||||
const LLStructType* infoTy;
|
||||
LLConstant* infoInit;
|
||||
LLConstant* info;
|
||||
|
||||
size_t index;
|
||||
|
||||
IrInterface(BaseClass* b);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "ir/irtype.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "mtype.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/logger.h"
|
||||
#include "ir/irtype.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const llvm::Type* DtoType(Type* dt);
|
||||
extern const llvm::Type* DtoSize_t();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrType::IrType(Type* dt, const llvm::Type* lt)
|
||||
: dtype(dt),
|
||||
@@ -10,6 +18,8 @@ IrType::IrType(Type* dt, const llvm::Type* lt)
|
||||
{
|
||||
assert(dt && "null D Type");
|
||||
assert(lt && "null LLVM Type");
|
||||
assert(dt->ir.type == NULL && "llvm type (old one) already set");
|
||||
dt->ir.type = &pa;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -23,6 +33,13 @@ IrTypeBasic::IrTypeBasic(Type * dt)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypeBasic::buildType()
|
||||
{
|
||||
return pa.get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypeBasic::basic2llvm(Type* t)
|
||||
{
|
||||
const llvm::Type* t2;
|
||||
@@ -101,19 +118,26 @@ const llvm::Type * IrTypeBasic::basic2llvm(Type* t)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrTypePointer::IrTypePointer(Type * dt)
|
||||
: IrType(dt, pointer2llvm(dt))
|
||||
: IrType(dt, llvm::OpaqueType::get())
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const llvm::Type* DtoType(Type* dt);
|
||||
|
||||
const llvm::Type * IrTypePointer::pointer2llvm(Type * t)
|
||||
const llvm::Type * IrTypePointer::buildType()
|
||||
{
|
||||
assert(t->ty == Tpointer && "not pointer type");
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(
|
||||
pointer2llvm(dtype));
|
||||
return pa.get();
|
||||
}
|
||||
|
||||
const llvm::Type* elemType = DtoType(t->nextOf());
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypePointer::pointer2llvm(Type * dt)
|
||||
{
|
||||
assert(dt->ty == Tpointer && "not pointer type");
|
||||
|
||||
const llvm::Type* elemType = DtoType(dt->nextOf());
|
||||
if (elemType == llvm::Type::VoidTy)
|
||||
elemType = llvm::Type::Int8Ty;
|
||||
return llvm::PointerType::get(elemType, 0);
|
||||
@@ -124,21 +148,26 @@ const llvm::Type * IrTypePointer::pointer2llvm(Type * t)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrTypeSArray::IrTypeSArray(Type * dt)
|
||||
: IrType(dt, sarray2llvm(dt))
|
||||
: IrType(dt, llvm::OpaqueType::get())
|
||||
{
|
||||
assert(dt->ty == Tsarray && "not static array type");
|
||||
TypeSArray* tsa = (TypeSArray*)dt;
|
||||
uint64_t d = (uint64_t)tsa->dim->toUInteger();
|
||||
assert(d == dim);
|
||||
dim = (uint64_t)tsa->dim->toUInteger();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypeSArray::buildType()
|
||||
{
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(
|
||||
sarray2llvm(dtype));
|
||||
return pa.get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypeSArray::sarray2llvm(Type * t)
|
||||
{
|
||||
assert(t->ty == Tsarray && "not static array type");
|
||||
|
||||
TypeSArray* tsa = (TypeSArray*)t;
|
||||
dim = (uint64_t)tsa->dim->toUInteger();
|
||||
const llvm::Type* elemType = DtoType(t->nextOf());
|
||||
if (elemType == llvm::Type::VoidTy)
|
||||
elemType = llvm::Type::Int8Ty;
|
||||
@@ -150,23 +179,38 @@ const llvm::Type * IrTypeSArray::sarray2llvm(Type * t)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrTypeArray::IrTypeArray(Type * dt)
|
||||
: IrType(dt, array2llvm(dt))
|
||||
: IrType(dt, llvm::OpaqueType::get())
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const llvm::Type* DtoSize_t();
|
||||
const llvm::Type * IrTypeArray::buildType()
|
||||
{
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(
|
||||
array2llvm(dtype));
|
||||
return pa.get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypeArray::array2llvm(Type * t)
|
||||
{
|
||||
assert(t->ty == Tarray && "not dynamic array type");
|
||||
|
||||
// get .ptr type
|
||||
const llvm::Type* elemType = DtoType(t->nextOf());
|
||||
if (elemType == llvm::Type::VoidTy)
|
||||
elemType = llvm::Type::Int8Ty;
|
||||
elemType = llvm::PointerType::get(elemType, 0);
|
||||
return llvm::StructType::get(DtoSize_t(), elemType, NULL);
|
||||
|
||||
// create struct type
|
||||
const llvm::Type* at = llvm::StructType::get(DtoSize_t(), elemType, NULL);
|
||||
|
||||
// name dynamic array types
|
||||
Type::sir->getState()->module->addTypeName(t->toChars(), at);
|
||||
|
||||
return at;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
35
ir/irtype.h
35
ir/irtype.h
@@ -9,10 +9,13 @@
|
||||
|
||||
struct Type;
|
||||
|
||||
class IrTypeAggr;
|
||||
class IrTypeArray;
|
||||
class IrTypeBasic;
|
||||
class IrTypeClass;
|
||||
class IrTypePointer;
|
||||
class IrTypeSArray;
|
||||
class IrTypeStruct;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -24,19 +27,29 @@ public:
|
||||
IrType(Type* dt, const llvm::Type* lt);
|
||||
|
||||
///
|
||||
Type* getD() { return dtype; }
|
||||
|
||||
///
|
||||
const llvm::Type* get() { return pa.get(); }
|
||||
|
||||
virtual IrTypeAggr* isAggr() { return NULL; }
|
||||
///
|
||||
virtual IrTypeArray* isArray() { return NULL; }
|
||||
///
|
||||
virtual IrTypeBasic* isBasic() { return NULL; }
|
||||
///
|
||||
virtual IrTypeClass* isClass() { return NULL; }
|
||||
///
|
||||
virtual IrTypePointer* isPointer() { return NULL; }
|
||||
///
|
||||
virtual IrTypeSArray* isSArray() { return NULL; }
|
||||
///
|
||||
virtual IrTypeStruct* isStruct() { return NULL; }
|
||||
|
||||
///
|
||||
Type* getD() { return dtype; }
|
||||
///
|
||||
virtual const llvm::Type* get() { return pa.get(); }
|
||||
///
|
||||
llvm::PATypeHolder& getPA() { return pa; }
|
||||
|
||||
///
|
||||
virtual const llvm::Type* buildType() = 0;
|
||||
|
||||
protected:
|
||||
///
|
||||
@@ -58,6 +71,9 @@ public:
|
||||
///
|
||||
IrTypeBasic* isBasic() { return this; }
|
||||
|
||||
///
|
||||
const llvm::Type* buildType();
|
||||
|
||||
protected:
|
||||
///
|
||||
const llvm::Type* basic2llvm(Type* t);
|
||||
@@ -75,6 +91,9 @@ public:
|
||||
///
|
||||
IrTypePointer* isPointer() { return this; }
|
||||
|
||||
///
|
||||
const llvm::Type* buildType();
|
||||
|
||||
protected:
|
||||
///
|
||||
const llvm::Type* pointer2llvm(Type* t);
|
||||
@@ -92,6 +111,9 @@ public:
|
||||
///
|
||||
IrTypeSArray* isSArray() { return this; }
|
||||
|
||||
///
|
||||
const llvm::Type* buildType();
|
||||
|
||||
protected:
|
||||
///
|
||||
const llvm::Type* sarray2llvm(Type* t);
|
||||
@@ -112,6 +134,9 @@ public:
|
||||
///
|
||||
IrTypeArray* isArray() { return this; }
|
||||
|
||||
///
|
||||
const llvm::Type* buildType();
|
||||
|
||||
protected:
|
||||
///
|
||||
const llvm::Type* array2llvm(Type* t);
|
||||
|
||||
236
ir/irtypeclass.cpp
Normal file
236
ir/irtypeclass.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "llvm/DerivedTypes.h"
|
||||
|
||||
#include "aggregate.h"
|
||||
#include "declaration.h"
|
||||
#include "dsymbol.h"
|
||||
#include "mtype.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/utils.h"
|
||||
#include "ir/irtypeclass.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrTypeClass::IrTypeClass(ClassDeclaration* cd)
|
||||
: IrTypeAggr(cd),
|
||||
cd(cd),
|
||||
tc((TypeClass*)cd->type),
|
||||
vtbl_pa(llvm::OpaqueType::get())
|
||||
{
|
||||
vtbl_size = cd->vtbl.dim;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IrTypeClass::addBaseClassData(
|
||||
std::vector< const llvm::Type * > & defaultTypes,
|
||||
ClassDeclaration * base,
|
||||
size_t & offset,
|
||||
size_t & field_index)
|
||||
{
|
||||
if (base->baseClass)
|
||||
{
|
||||
addBaseClassData(defaultTypes, 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);
|
||||
if (vd->ir.irField == NULL)
|
||||
{
|
||||
new IrField(vd, 2, vd->offset - PTRSIZE * 2);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
|
||||
|
||||
// get next aligned offset for this type
|
||||
size_t alignsize = vd->type->alignsize();
|
||||
size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
|
||||
|
||||
// do we need to insert explicit padding before the field?
|
||||
if (alignedoffset < vd->offset)
|
||||
{
|
||||
field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
|
||||
}
|
||||
|
||||
// add default type
|
||||
defaultTypes.push_back(DtoType(vd->type));
|
||||
|
||||
// advance offset to right past this field
|
||||
offset = vd->offset + vd->type->size();
|
||||
|
||||
// give field index
|
||||
// the IrField creation doesn't really belong here, but it's a trivial operation
|
||||
// and it save yet another of these loops.
|
||||
IF_LOG Logger::println("Field index: %zu", field_index);
|
||||
if (vd->ir.irField == NULL)
|
||||
{
|
||||
new IrField(vd, field_index);
|
||||
}
|
||||
field_index++;
|
||||
}
|
||||
|
||||
// any interface implementations?
|
||||
if (base->vtblInterfaces)
|
||||
{
|
||||
bool new_instances = (base == cd);
|
||||
|
||||
ArrayIter<BaseClass> it2(*base->vtblInterfaces);
|
||||
|
||||
for (; !it2.done(); it2.next())
|
||||
{
|
||||
BaseClass* b = it2.get();
|
||||
IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars());
|
||||
|
||||
Array arr;
|
||||
b->fillVtbl(cd, &arr, new_instances);
|
||||
|
||||
const llvm::Type* ivtbl_type = buildVtblType(Type::tvoid->pointerTo(), &arr);
|
||||
defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0));
|
||||
|
||||
offset += PTRSIZE;
|
||||
|
||||
// add to the interface map
|
||||
if (interfaceMap.find(b->base) == interfaceMap.end())
|
||||
interfaceMap.insert(std::make_pair(b->base, field_index));
|
||||
field_index++;
|
||||
}
|
||||
}
|
||||
|
||||
// tail padding?
|
||||
if (offset < base->structsize)
|
||||
{
|
||||
field_index += add_zeros(defaultTypes, base->structsize - offset);
|
||||
offset = base->structsize;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type* IrTypeClass::buildType()
|
||||
{
|
||||
IF_LOG Logger::println("Building class type %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<const llvm::Type*> defaultTypes;
|
||||
defaultTypes.reserve(32);
|
||||
|
||||
// add vtbl
|
||||
defaultTypes.push_back(llvm::PointerType::get(vtbl_pa.get(), 0));
|
||||
|
||||
// interface are just a vtable
|
||||
if (!cd->isInterfaceDeclaration())
|
||||
{
|
||||
// add monitor
|
||||
defaultTypes.push_back(llvm::PointerType::get(llvm::Type::Int8Ty, 0));
|
||||
|
||||
// we start right after the vtbl and monitor
|
||||
size_t offset = PTRSIZE * 2;
|
||||
size_t field_index = 2;
|
||||
|
||||
// add data members recursively
|
||||
addBaseClassData(defaultTypes, cd, offset, field_index);
|
||||
}
|
||||
|
||||
// errors are fatal during codegen
|
||||
if (global.errors)
|
||||
fatal();
|
||||
|
||||
// build the llvm type
|
||||
const llvm::Type* st = llvm::StructType::get(defaultTypes, false);
|
||||
|
||||
// refine type
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(st);
|
||||
|
||||
// name type
|
||||
Type::sir->getState()->module->addTypeName(cd->toPrettyChars(), pa.get());
|
||||
|
||||
// VTBL
|
||||
|
||||
// build vtbl type
|
||||
const llvm::Type* vtblty = buildVtblType(
|
||||
ClassDeclaration::classinfo->type,
|
||||
&cd->vtbl);
|
||||
|
||||
// refine vtbl pa
|
||||
llvm::cast<llvm::OpaqueType>(vtbl_pa.get())->refineAbstractTypeTo(vtblty);
|
||||
|
||||
// name vtbl type
|
||||
std::string name(cd->toPrettyChars());
|
||||
name.append(".__vtbl");
|
||||
Type::sir->getState()->module->addTypeName(name, vtbl_pa.get());
|
||||
|
||||
#if 0
|
||||
IF_LOG Logger::cout() << "class type: " << *pa.get() << std::endl;
|
||||
#endif
|
||||
|
||||
return get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type* IrTypeClass::buildVtblType(Type* first, Array* vtbl_array)
|
||||
{
|
||||
IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
std::vector<const llvm::Type*> types;
|
||||
types.reserve(vtbl_array->dim);
|
||||
|
||||
// first comes the classinfo
|
||||
types.push_back(DtoType(first));
|
||||
|
||||
// then come the functions
|
||||
ArrayIter<Dsymbol> it(*vtbl_array);
|
||||
it.index = 1;
|
||||
|
||||
for (; !it.done(); it.next())
|
||||
{
|
||||
FuncDeclaration* fd = it.get()->isFuncDeclaration();
|
||||
assert(fd && "invalid vtbl entry");
|
||||
|
||||
IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars());
|
||||
|
||||
types.push_back(DtoType(fd->type->pointerTo()));
|
||||
}
|
||||
|
||||
// build the vtbl llvm type
|
||||
return llvm::StructType::get(types, false);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::Type * IrTypeClass::get()
|
||||
{
|
||||
return llvm::PointerType::get(pa.get(), 0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t IrTypeClass::getInterfaceIndex(ClassDeclaration * inter)
|
||||
{
|
||||
ClassIndexMap::iterator it = interfaceMap.find(inter);
|
||||
if (it == interfaceMap.end())
|
||||
return ~0;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
65
ir/irtypeclass.h
Normal file
65
ir/irtypeclass.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef __LDC_IR_IRTYPECLASS_H__
|
||||
#define __LDC_IR_IRTYPECLASS_H__
|
||||
|
||||
#include "ir/irtypestruct.h"
|
||||
|
||||
///
|
||||
class IrTypeClass : public IrTypeAggr
|
||||
{
|
||||
public:
|
||||
///
|
||||
IrTypeClass(ClassDeclaration* cd);
|
||||
|
||||
///
|
||||
virtual IrTypeClass* isClass() { return this; }
|
||||
|
||||
///
|
||||
const llvm::Type* buildType();
|
||||
|
||||
///
|
||||
const llvm::Type* getVtbl() { return vtbl_pa.get(); }
|
||||
|
||||
///
|
||||
const llvm::Type* get();
|
||||
|
||||
/// Get index to interface implementation.
|
||||
/// Returns the index of a specific interface implementation in this
|
||||
/// class or ~0 if not found.
|
||||
size_t getInterfaceIndex(ClassDeclaration* inter);
|
||||
|
||||
/// Returns the total number of pointers in the vtable.
|
||||
unsigned getVtblSize() { return vtbl_size; }
|
||||
|
||||
protected:
|
||||
///
|
||||
ClassDeclaration* cd;
|
||||
///
|
||||
TypeClass* tc;
|
||||
|
||||
///
|
||||
llvm::PATypeHolder vtbl_pa;
|
||||
|
||||
/// Number of pointers in vtable.
|
||||
unsigned vtbl_size;
|
||||
|
||||
/// std::map type mapping ClassDeclaration* to size_t.
|
||||
typedef std::map<ClassDeclaration*, size_t> ClassIndexMap;
|
||||
|
||||
/// Map for mapping the index of a specific interface implementation
|
||||
/// in this class to it's ClassDeclaration*.
|
||||
ClassIndexMap interfaceMap;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///
|
||||
const llvm::Type* buildVtblType(Type* first, Array* vtbl_array);
|
||||
|
||||
///
|
||||
void addBaseClassData(
|
||||
std::vector<const llvm::Type*>& defaultTypes,
|
||||
ClassDeclaration* base,
|
||||
size_t& offset,
|
||||
size_t& field_index);
|
||||
};
|
||||
|
||||
#endif
|
||||
148
ir/irtypestruct.cpp
Normal file
148
ir/irtypestruct.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "llvm/DerivedTypes.h"
|
||||
|
||||
#include "aggregate.h"
|
||||
#include "declaration.h"
|
||||
#include "mtype.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/utils.h"
|
||||
#include "ir/irtypestruct.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrTypeAggr::IrTypeAggr(AggregateDeclaration * ad)
|
||||
: IrType(ad->type, llvm::OpaqueType::get()),
|
||||
aggr(ad)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrTypeStruct::IrTypeStruct(StructDeclaration * sd)
|
||||
: IrTypeAggr(sd),
|
||||
sd(sd),
|
||||
ts((TypeStruct*)sd->type)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff)
|
||||
{
|
||||
size_t n = defaultTypes.size();
|
||||
while (diff)
|
||||
{
|
||||
if (global.params.is64bit && diff % 8 == 0)
|
||||
{
|
||||
defaultTypes.push_back(llvm::Type::Int64Ty);
|
||||
diff -= 8;
|
||||
}
|
||||
else if (diff % 4 == 0)
|
||||
{
|
||||
defaultTypes.push_back(llvm::Type::Int32Ty);
|
||||
diff -= 4;
|
||||
}
|
||||
else if (diff % 2 == 0)
|
||||
{
|
||||
defaultTypes.push_back(llvm::Type::Int16Ty);
|
||||
diff -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultTypes.push_back(llvm::Type::Int8Ty);
|
||||
diff -= 1;
|
||||
}
|
||||
}
|
||||
return defaultTypes.size() - n;
|
||||
}
|
||||
|
||||
const llvm::Type* IrTypeStruct::buildType()
|
||||
{
|
||||
IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->locToChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// find the fields that contribute to the default initializer.
|
||||
// these will define the default type.
|
||||
|
||||
std::vector<const llvm::Type*> defaultTypes;
|
||||
defaultTypes.reserve(16);
|
||||
|
||||
size_t offset = 0;
|
||||
size_t field_index = 0;
|
||||
|
||||
bool packed = (sd->type->alignsize() == 1);
|
||||
|
||||
ArrayIter<VarDeclaration> it(sd->fields);
|
||||
for (; !it.done(); it.next())
|
||||
{
|
||||
VarDeclaration* vd = it.get();
|
||||
|
||||
assert(vd->ir.irField == NULL && "struct inheritance is not allowed, how can this happen?");
|
||||
|
||||
// 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);
|
||||
new IrField(vd, 0, vd->offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
|
||||
|
||||
// get next aligned offset for this type
|
||||
size_t alignedoffset = offset;
|
||||
if (!packed)
|
||||
{
|
||||
size_t alignsize = vd->type->alignsize();
|
||||
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
|
||||
}
|
||||
|
||||
// insert explicit padding?
|
||||
if (alignedoffset < vd->offset)
|
||||
{
|
||||
field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
|
||||
}
|
||||
|
||||
// add default type
|
||||
defaultTypes.push_back(DtoType(vd->type));
|
||||
|
||||
// advance offset to right past this field
|
||||
offset = vd->offset + vd->type->size();
|
||||
|
||||
// give field index
|
||||
// the IrField creation doesn't really belong here, but it's a trivial operation
|
||||
// and it save yet another of these loops.
|
||||
IF_LOG Logger::println("Field index: %zu", field_index);
|
||||
new IrField(vd, field_index);
|
||||
field_index++;
|
||||
}
|
||||
|
||||
// tail padding?
|
||||
if (offset < sd->structsize)
|
||||
{
|
||||
add_zeros(defaultTypes, sd->structsize - offset);
|
||||
}
|
||||
|
||||
// build the llvm type
|
||||
const llvm::Type* st = llvm::StructType::get(defaultTypes, packed);
|
||||
|
||||
// refine type
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(st);
|
||||
|
||||
// name types
|
||||
Type::sir->getState()->module->addTypeName(sd->toPrettyChars(), pa.get());
|
||||
|
||||
#if 0
|
||||
IF_LOG Logger::cout() << "struct type: " << *pa.get() << std::endl;
|
||||
#endif
|
||||
|
||||
return pa.get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
52
ir/irtypestruct.h
Normal file
52
ir/irtypestruct.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef __LDC_IR_IRTYPESTRUCT_H__
|
||||
#define __LDC_IR_IRTYPESTRUCT_H__
|
||||
|
||||
#include "ir/irtype.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct AggregateDeclaration;
|
||||
struct StructDeclaration;
|
||||
struct TypeStruct;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class IrTypeAggr : public IrType
|
||||
{
|
||||
public:
|
||||
///
|
||||
IrTypeAggr(AggregateDeclaration* ad);
|
||||
|
||||
///
|
||||
IrTypeAggr* isAggr() { return this; }
|
||||
|
||||
protected:
|
||||
/// AggregateDeclaration this type represents.
|
||||
AggregateDeclaration* aggr;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class IrTypeStruct : public IrTypeAggr
|
||||
{
|
||||
public:
|
||||
///
|
||||
IrTypeStruct(StructDeclaration* sd);
|
||||
|
||||
///
|
||||
IrTypeStruct* isStruct() { return this; }
|
||||
|
||||
///
|
||||
const llvm::Type* buildType();
|
||||
|
||||
protected:
|
||||
/// StructDeclaration this type represents.
|
||||
StructDeclaration* sd;
|
||||
|
||||
/// DMD TypeStruct of this type.
|
||||
TypeStruct* ts;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif
|
||||
@@ -36,11 +36,14 @@ IrLocal::IrLocal(VarDeclaration* v) : IrVar(v)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrField::IrField(VarDeclaration* v) : IrVar(v)
|
||||
IrField::IrField(VarDeclaration* v, size_t idx, size_t offset) : IrVar(v)
|
||||
{
|
||||
index = 0;
|
||||
unionOffset = 0;
|
||||
index = idx;
|
||||
unionOffset = offset;
|
||||
constInit = NULL;
|
||||
|
||||
assert(V->ir.irField == NULL && "field for this variable already exists");
|
||||
V->ir.irField = this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -34,11 +34,12 @@ struct IrLocal : IrVar
|
||||
// represents an aggregate field variable
|
||||
struct IrField : IrVar
|
||||
{
|
||||
IrField(VarDeclaration* v);
|
||||
IrField(VarDeclaration* v, size_t idx, size_t offset = 0);
|
||||
|
||||
unsigned index;
|
||||
unsigned unionOffset;
|
||||
|
||||
protected:
|
||||
llvm::Constant* constInit;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user