mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-07 19:36:06 +03:00
[svn r104] TONS OF FIXES.
Split up declaration, constant initializer gen and definition for globals, structs, classes and functions. Improved ClassInfo support (not complete), not in vtable yet. Fixed a bunch of forward reference problems. Much more. Major commit! :)
This commit is contained in:
parent
7d6bbcd87d
commit
d1cfe9524c
35 changed files with 1824 additions and 1452 deletions
|
@ -1,5 +1,4 @@
|
|||
//import std.stdio, std.math, std.string;
|
||||
//import tools.base;
|
||||
import std.stdio;
|
||||
|
||||
int atoi(char[] s) {
|
||||
int i, fac=1;
|
||||
|
@ -105,7 +104,7 @@ void main(string[] args) {
|
|||
n = (args.length==3 ? args[2].atoi() : 512), ss = 4;
|
||||
auto light = Vec(-1, -3, 2).unitise();
|
||||
auto s=create(level, Vec(0, -1, 0), 1);
|
||||
printf("P5\n%d %d\n255", n, n);
|
||||
writefln("P5\n", n, " ", n, "\n255");
|
||||
for (int y=n-1; y>=0; --y)
|
||||
for (int x=0; x<n; ++x) {
|
||||
double g=0;
|
||||
|
|
|
@ -43,8 +43,9 @@ namespace llvm
|
|||
class Value;
|
||||
class Constant;
|
||||
class ConstantStruct;
|
||||
class GlobalVariable;
|
||||
}
|
||||
|
||||
struct IRStruct;
|
||||
struct DUnion;
|
||||
|
||||
struct AggregateDeclaration : ScopeDsymbol
|
||||
|
@ -101,12 +102,14 @@ struct AggregateDeclaration : ScopeDsymbol
|
|||
Symbol *toInitializer();
|
||||
|
||||
bool llvmInProgress;
|
||||
const llvm::Type* llvmType;
|
||||
llvm::Constant* llvmVtbl;
|
||||
llvm::GlobalVariable* llvmVtbl;
|
||||
llvm::ConstantStruct* llvmConstVtbl;
|
||||
llvm::Constant* llvmInitZ;
|
||||
llvm::GlobalVariable* llvmClass;
|
||||
llvm::Constant* llvmClassZ;
|
||||
bool llvmHasUnions;
|
||||
DUnion* llvmUnion;
|
||||
IRStruct* llvmIRStruct;
|
||||
|
||||
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
||||
};
|
||||
|
|
|
@ -32,7 +32,6 @@ Declaration::Declaration(Identifier *id)
|
|||
storage_class = STCundefined;
|
||||
protection = PROTundefined;
|
||||
linkage = LINKdefault;
|
||||
llvmTouched = false;
|
||||
}
|
||||
|
||||
void Declaration::semantic(Scope *sc)
|
||||
|
@ -553,6 +552,8 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer
|
|||
llvmFieldIndex = -1;
|
||||
llvmFieldIndexOffset = 0;
|
||||
llvmNeedsStorage = false;
|
||||
llvmConstInit = NULL;
|
||||
llvmIRGlobal = NULL;
|
||||
}
|
||||
|
||||
Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
namespace llvm {
|
||||
class Value;
|
||||
}
|
||||
struct IRFunction;
|
||||
struct IRGlobal;
|
||||
|
||||
struct Expression;
|
||||
struct Statement;
|
||||
|
@ -128,8 +130,6 @@ struct Declaration : Dsymbol
|
|||
Declaration *isDeclaration() { return this; }
|
||||
|
||||
virtual void toObjFile(); // compile to .obj file
|
||||
|
||||
bool llvmTouched;
|
||||
};
|
||||
|
||||
/**************************************************************/
|
||||
|
@ -263,6 +263,8 @@ struct VarDeclaration : Declaration
|
|||
int llvmFieldIndex;
|
||||
size_t llvmFieldIndexOffset;
|
||||
bool llvmNeedsStorage;
|
||||
llvm::Constant* llvmConstInit;
|
||||
IRGlobal* llvmIRGlobal;
|
||||
};
|
||||
|
||||
/**************************************************************/
|
||||
|
@ -293,6 +295,8 @@ struct ClassInfoDeclaration : VarDeclaration
|
|||
void emitComment(Scope *sc);
|
||||
|
||||
Symbol *toSymbol();
|
||||
|
||||
ClassInfoDeclaration* isClassInfoDeclaration() { return this; }
|
||||
};
|
||||
|
||||
struct ModuleInfoDeclaration : VarDeclaration
|
||||
|
@ -558,6 +562,7 @@ struct FuncDeclaration : Declaration
|
|||
llvm::Value* llvmArgPtr;
|
||||
llvm::Constant* llvmDwarfSubProgram;
|
||||
bool llvmRunTimeHack;
|
||||
IRFunction* llvmIRFunc;
|
||||
};
|
||||
|
||||
struct FuncAliasDeclaration : FuncDeclaration
|
||||
|
|
|
@ -48,6 +48,7 @@ Dsymbol::Dsymbol()
|
|||
this->llvmInternal2 = NULL;
|
||||
this->llvmValue = NULL;
|
||||
this->llvmDModule = NULL;
|
||||
this->llvmTouched = false;
|
||||
}
|
||||
|
||||
Dsymbol::Dsymbol(Identifier *ident)
|
||||
|
@ -65,6 +66,7 @@ Dsymbol::Dsymbol(Identifier *ident)
|
|||
this->llvmInternal2 = NULL;
|
||||
this->llvmValue = NULL;
|
||||
this->llvmDModule = NULL;
|
||||
this->llvmTouched = false;
|
||||
}
|
||||
|
||||
int Dsymbol::equals(Object *o)
|
||||
|
|
|
@ -67,6 +67,7 @@ struct Expression;
|
|||
struct DeleteDeclaration;
|
||||
struct HdrGenState;
|
||||
struct TypeInfoDeclaration;
|
||||
struct ClassInfoDeclaration;
|
||||
|
||||
#if IN_GCC
|
||||
union tree_node;
|
||||
|
@ -212,6 +213,7 @@ struct Dsymbol : Object
|
|||
virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
|
||||
virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
|
||||
virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; }
|
||||
virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; }
|
||||
|
||||
// llvm stuff
|
||||
int llvmInternal;
|
||||
|
@ -220,6 +222,8 @@ struct Dsymbol : Object
|
|||
|
||||
llvm::Value* llvmValue;
|
||||
Module* llvmDModule;
|
||||
|
||||
bool llvmTouched;
|
||||
};
|
||||
|
||||
// Dsymbol that generates a scope
|
||||
|
|
|
@ -80,6 +80,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
|||
llvmArgPtr = NULL;
|
||||
llvmDwarfSubProgram = NULL;
|
||||
llvmRunTimeHack = false;
|
||||
llvmIRFunc = NULL;
|
||||
}
|
||||
|
||||
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
||||
|
|
11
dmd/mtype.h
11
dmd/mtype.h
|
@ -21,11 +21,14 @@
|
|||
#include "arraytypes.h"
|
||||
#include "expression.h"
|
||||
|
||||
// LLVMDC
|
||||
namespace llvm
|
||||
{
|
||||
class Value;
|
||||
class Type;
|
||||
class Instruction;
|
||||
class Type;
|
||||
class PATypeHolder;
|
||||
class GlobalVariable;
|
||||
}
|
||||
|
||||
struct Scope;
|
||||
|
@ -250,7 +253,7 @@ struct Type : Object
|
|||
virtual type *toCParamtype();
|
||||
virtual Symbol *toSymbol();
|
||||
|
||||
const llvm::Type* llvmType;
|
||||
llvm::PATypeHolder* llvmType;
|
||||
|
||||
// For eliminating dynamic_cast
|
||||
virtual TypeBasic *isTypeBasic();
|
||||
|
@ -540,7 +543,7 @@ struct TypeStruct : Type
|
|||
|
||||
type *toCtype();
|
||||
|
||||
llvm::Constant* llvmInit;
|
||||
llvm::GlobalVariable* llvmInit;
|
||||
};
|
||||
|
||||
struct TypeEnum : Type
|
||||
|
@ -638,7 +641,7 @@ struct TypeClass : Type
|
|||
|
||||
Symbol *toSymbol();
|
||||
|
||||
llvm::Constant* llvmInit;
|
||||
llvm::GlobalVariable* llvmInit;
|
||||
};
|
||||
|
||||
struct TypeTuple : Type
|
||||
|
|
|
@ -45,13 +45,15 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
|
|||
sinit = NULL;
|
||||
scope = NULL;
|
||||
|
||||
llvmType = NULL;
|
||||
llvmVtbl = NULL;
|
||||
llvmConstVtbl = NULL;
|
||||
llvmInitZ = NULL;
|
||||
llvmClass = NULL;
|
||||
llvmClassZ = NULL;
|
||||
llvmInProgress = false;
|
||||
llvmHasUnions = false;
|
||||
llvmUnion = NULL;
|
||||
llvmIRStruct = NULL;
|
||||
}
|
||||
|
||||
enum PROT AggregateDeclaration::prot()
|
||||
|
|
|
@ -42,7 +42,7 @@ const llvm::StructType* DtoArrayType(Type* t)
|
|||
const llvm::ArrayType* DtoStaticArrayType(Type* t)
|
||||
{
|
||||
if (t->llvmType)
|
||||
return isaArray(t->llvmType);
|
||||
return isaArray(t->llvmType->get());
|
||||
|
||||
assert(t->ty == Tsarray);
|
||||
assert(t->next);
|
||||
|
@ -53,7 +53,8 @@ const llvm::ArrayType* DtoStaticArrayType(Type* t)
|
|||
assert(tsa->dim->type->isintegral());
|
||||
const llvm::ArrayType* arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger());
|
||||
|
||||
tsa->llvmType = arrty;
|
||||
assert(!tsa->llvmType);
|
||||
tsa->llvmType = new llvm::PATypeHolder(arrty);
|
||||
return arrty;
|
||||
}
|
||||
|
||||
|
@ -547,7 +548,7 @@ void DtoCatArrays(llvm::Value* arr, Expression* exp1, Expression* exp2)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// helper for eq and cmp
|
||||
static llvm::Value* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r)
|
||||
static llvm::Value* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r, bool useti)
|
||||
{
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, func);
|
||||
assert(fn);
|
||||
|
@ -588,6 +589,8 @@ static llvm::Value* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r)
|
|||
args.push_back(DtoBitCast(lmem,pt));
|
||||
args.push_back(DtoBitCast(rmem,pt));
|
||||
|
||||
// pass element typeinfo ?
|
||||
if (useti) {
|
||||
TypeInfoDeclaration* ti = DtoDType(l->getType())->next->getTypeInfoDeclaration();
|
||||
if (!ti->llvmValue) {
|
||||
ti->toObjFile();
|
||||
|
@ -596,6 +599,7 @@ static llvm::Value* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r)
|
|||
|
||||
pt = fn->getFunctionType()->getParamType(2);
|
||||
args.push_back(DtoBitCast(ti->llvmValue, pt));
|
||||
}
|
||||
|
||||
return gIR->ir->CreateCall(fn, args.begin(), args.end(), "tmp");
|
||||
}
|
||||
|
@ -606,7 +610,7 @@ llvm::Value* DtoArrayEquals(TOK op, DValue* l, DValue* r)
|
|||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_adEq");
|
||||
assert(fn);
|
||||
|
||||
llvm::Value* res = DtoArrayEqCmp_impl("_adEq", l, r);
|
||||
llvm::Value* res = DtoArrayEqCmp_impl("_adEq", l, r, true);
|
||||
if (op == TOKnotequal)
|
||||
res = gIR->ir->CreateNot(res, "tmp");
|
||||
|
||||
|
@ -660,7 +664,11 @@ llvm::Value* DtoArrayCompare(TOK op, DValue* l, DValue* r)
|
|||
|
||||
if (!skip)
|
||||
{
|
||||
res = DtoArrayEqCmp_impl("_adCmp", l, r);
|
||||
Type* t = DtoDType(DtoDType(l->getType())->next);
|
||||
if (t->ty == Tchar)
|
||||
res = DtoArrayEqCmp_impl("_adCmpChar", l, r, false);
|
||||
else
|
||||
res = DtoArrayEqCmp_impl("_adCmp", l, r, true);
|
||||
res = new llvm::ICmpInst(cmpop, res, DtoConstInt(0), "tmp", gIR->scopebb());
|
||||
}
|
||||
|
||||
|
|
431
gen/classes.cpp
Normal file
431
gen/classes.cpp
Normal file
|
@ -0,0 +1,431 @@
|
|||
#include "gen/llvm.h"
|
||||
|
||||
#include "mtype.h"
|
||||
#include "aggregate.h"
|
||||
#include "init.h"
|
||||
#include "declaration.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/classes.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void LLVM_AddBaseClassData(BaseClasses* bcs)
|
||||
{
|
||||
// add base class data members first
|
||||
for (int j=0; j<bcs->dim; j++)
|
||||
{
|
||||
BaseClass* bc = (BaseClass*)(bcs->data[j]);
|
||||
assert(bc);
|
||||
Logger::println("Adding base class members of %s", bc->base->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
bc->base->toObjFile();
|
||||
|
||||
LLVM_AddBaseClassData(&bc->base->baseclasses);
|
||||
for (int k=0; k < bc->base->members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]);
|
||||
if (dsym->isVarDeclaration())
|
||||
{
|
||||
dsym->toObjFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDeclareClass(ClassDeclaration* cd)
|
||||
{
|
||||
if (cd->llvmTouched) return;
|
||||
cd->llvmTouched = true;
|
||||
|
||||
Logger::println("DtoDeclareClass(%s)\n", cd->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
assert(cd->type->ty == Tclass);
|
||||
TypeClass* ts = (TypeClass*)cd->type;
|
||||
|
||||
assert(!cd->llvmIRStruct);
|
||||
IRStruct* irstruct = new IRStruct(ts);
|
||||
cd->llvmIRStruct = irstruct;
|
||||
|
||||
gIR->structs.push_back(irstruct);
|
||||
gIR->classes.push_back(cd);
|
||||
|
||||
// add vtable
|
||||
llvm::PATypeHolder pa = llvm::OpaqueType::get();
|
||||
const llvm::Type* vtabty = llvm::PointerType::get(pa);
|
||||
|
||||
std::vector<const llvm::Type*> fieldtypes;
|
||||
fieldtypes.push_back(vtabty);
|
||||
|
||||
// base classes first
|
||||
LLVM_AddBaseClassData(&cd->baseclasses);
|
||||
|
||||
// then add own members
|
||||
for (int k=0; k < cd->members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]);
|
||||
dsym->toObjFile();
|
||||
}
|
||||
|
||||
// add field types
|
||||
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
|
||||
fieldtypes.push_back(i->second.type);
|
||||
}
|
||||
|
||||
const llvm::StructType* structtype = llvm::StructType::get(fieldtypes);
|
||||
// refine abstract types for stuff like: class C {C next;}
|
||||
assert(irstruct->recty != 0);
|
||||
{
|
||||
llvm::PATypeHolder& spa = irstruct->recty;
|
||||
llvm::cast<llvm::OpaqueType>(spa.get())->refineAbstractTypeTo(structtype);
|
||||
structtype = isaStruct(spa.get());
|
||||
}
|
||||
|
||||
// create the type
|
||||
ts->llvmType = new llvm::PATypeHolder(structtype);
|
||||
|
||||
bool needs_definition = false;
|
||||
if (cd->parent->isModule()) {
|
||||
gIR->module->addTypeName(cd->mangle(), ts->llvmType->get());
|
||||
needs_definition = (cd->getModule() == gIR->dmodule);
|
||||
}
|
||||
else {
|
||||
assert(0 && "class parent is not a module");
|
||||
}
|
||||
|
||||
// generate vtable
|
||||
llvm::GlobalVariable* svtblVar = 0;
|
||||
std::vector<llvm::Constant*> sinits;
|
||||
std::vector<const llvm::Type*> sinits_ty;
|
||||
sinits.reserve(cd->vtbl.dim);
|
||||
sinits_ty.reserve(cd->vtbl.dim);
|
||||
|
||||
for (int k=0; k < cd->vtbl.dim; k++)
|
||||
{
|
||||
Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k];
|
||||
assert(dsym);
|
||||
//Logger::cout() << "vtblsym: " << dsym->toChars() << '\n';
|
||||
|
||||
if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
|
||||
fd->toObjFile();
|
||||
assert(fd->llvmValue);
|
||||
llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
|
||||
sinits.push_back(c);
|
||||
sinits_ty.push_back(c->getType());
|
||||
}
|
||||
else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
|
||||
const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
llvm::Constant* c = llvm::Constant::getNullValue(cty);
|
||||
sinits.push_back(c);
|
||||
sinits_ty.push_back(cty);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
const llvm::StructType* svtbl_ty = 0;
|
||||
if (!sinits.empty())
|
||||
{
|
||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
|
||||
std::string varname("_D");
|
||||
varname.append(cd->mangle());
|
||||
varname.append("6__vtblZ");
|
||||
|
||||
std::string styname(cd->mangle());
|
||||
styname.append("__vtblTy");
|
||||
|
||||
svtbl_ty = llvm::StructType::get(sinits_ty);
|
||||
gIR->module->addTypeName(styname, svtbl_ty);
|
||||
svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module);
|
||||
|
||||
cd->llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits));
|
||||
if (needs_definition)
|
||||
svtblVar->setInitializer(cd->llvmConstVtbl);
|
||||
cd->llvmVtbl = svtblVar;
|
||||
}
|
||||
|
||||
// refine for final vtable type
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty);
|
||||
|
||||
std::string initname("_D");
|
||||
initname.append(cd->mangle());
|
||||
initname.append("6__initZ");
|
||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module);
|
||||
ts->llvmInit = initvar;
|
||||
|
||||
gIR->classes.pop_back();
|
||||
gIR->structs.pop_back();
|
||||
|
||||
gIR->constInitQueue.push_back(cd);
|
||||
if (needs_definition)
|
||||
gIR->defineQueue.push_back(cd);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoConstInitClass(ClassDeclaration* cd)
|
||||
{
|
||||
IRStruct* irstruct = cd->llvmIRStruct;
|
||||
if (irstruct->constinited) return;
|
||||
irstruct->constinited = true;
|
||||
|
||||
Logger::println("DtoConstInitClass(%s)\n", cd->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
gIR->structs.push_back(irstruct);
|
||||
gIR->classes.push_back(cd);
|
||||
|
||||
// make sure each offset knows its default initializer
|
||||
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i)
|
||||
{
|
||||
IRStruct::Offset* so = &i->second;
|
||||
llvm::Constant* finit = DtoConstFieldInitializer(so->var->type, so->var->init);
|
||||
so->init = finit;
|
||||
so->var->llvmConstInit = finit;
|
||||
}
|
||||
|
||||
// fill out fieldtypes/inits
|
||||
std::vector<llvm::Constant*> fieldinits;
|
||||
|
||||
// first field is always the vtable
|
||||
assert(cd->llvmVtbl != 0);
|
||||
fieldinits.push_back(cd->llvmVtbl);
|
||||
|
||||
// rest
|
||||
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
|
||||
fieldinits.push_back(i->second.init);
|
||||
}
|
||||
|
||||
// get the struct (class) type
|
||||
assert(cd->type->ty == Tclass);
|
||||
TypeClass* ts = (TypeClass*)cd->type;
|
||||
const llvm::StructType* structtype = isaStruct(ts->llvmType->get());
|
||||
|
||||
// generate initializer
|
||||
Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n';
|
||||
Logger::println("%u %u fields", structtype->getNumElements(), fieldinits.size());
|
||||
llvm::Constant* _init = llvm::ConstantStruct::get(structtype, fieldinits);
|
||||
assert(_init);
|
||||
cd->llvmInitZ = _init;
|
||||
|
||||
gIR->classes.pop_back();
|
||||
gIR->structs.pop_back();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDefineClass(ClassDeclaration* cd)
|
||||
{
|
||||
IRStruct* irstruct = cd->llvmIRStruct;
|
||||
if (irstruct->defined) return;
|
||||
irstruct->defined = true;
|
||||
|
||||
Logger::println("DtoDefineClass(%s)\n", cd->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// get the struct (class) type
|
||||
assert(cd->type->ty == Tclass);
|
||||
TypeClass* ts = (TypeClass*)cd->type;
|
||||
|
||||
bool def = false;
|
||||
if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) {
|
||||
ts->llvmInit->setInitializer(cd->llvmInitZ);
|
||||
def = true;
|
||||
}
|
||||
|
||||
// generate classinfo
|
||||
DtoDeclareClassInfo(cd);
|
||||
if (def) DtoDefineClassInfo(cd);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
|
||||
{
|
||||
Array* arr = &tc->sym->dtors;
|
||||
for (size_t i=0; i<arr->dim; i++)
|
||||
{
|
||||
FuncDeclaration* fd = (FuncDeclaration*)arr->data[i];
|
||||
assert(fd->llvmValue);
|
||||
new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoInitClass(TypeClass* tc, llvm::Value* dst)
|
||||
{
|
||||
assert(gIR);
|
||||
|
||||
assert(tc->llvmType);
|
||||
uint64_t size_t_size = gTargetData->getTypeSize(DtoSize_t());
|
||||
uint64_t n = gTargetData->getTypeSize(tc->llvmType->get()) - size_t_size;
|
||||
|
||||
// set vtable field
|
||||
llvm::Value* vtblvar = DtoGEPi(dst,0,0,"tmp",gIR->scopebb());
|
||||
assert(tc->sym->llvmVtbl);
|
||||
new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb());
|
||||
|
||||
// copy the static initializer
|
||||
if (n > 0) {
|
||||
assert(tc->llvmInit);
|
||||
assert(dst->getType() == tc->llvmInit->getType());
|
||||
|
||||
llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
|
||||
llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
|
||||
dstarr = DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb());
|
||||
|
||||
llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb());
|
||||
srcarr = DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb());
|
||||
|
||||
llvm::Function* fn = LLVM_DeclareMemCpy32();
|
||||
std::vector<llvm::Value*> llargs;
|
||||
llargs.resize(4);
|
||||
llargs[0] = dstarr;
|
||||
llargs[1] = srcarr;
|
||||
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
|
||||
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
||||
|
||||
new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDeclareClassInfo(ClassDeclaration* cd)
|
||||
{
|
||||
if (cd->llvmClass)
|
||||
return;
|
||||
|
||||
Logger::println("CLASS INFO DECLARATION: %s", cd->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
|
||||
cinfo->toObjFile();
|
||||
|
||||
const llvm::Type* st = cinfo->type->llvmType->get();
|
||||
|
||||
std::string gname("_D");
|
||||
gname.append(cd->mangle());
|
||||
gname.append("7__ClassZ");
|
||||
|
||||
cd->llvmClass = new llvm::GlobalVariable(st, true, llvm::GlobalValue::ExternalLinkage, NULL, gname, gIR->module);
|
||||
}
|
||||
|
||||
void DtoDefineClassInfo(ClassDeclaration* cd)
|
||||
{
|
||||
// The layout is:
|
||||
// {
|
||||
// void **vptr;
|
||||
// monitor_t monitor;
|
||||
// byte[] initializer; // static initialization data
|
||||
// char[] name; // class name
|
||||
// void *[] vtbl;
|
||||
// Interface[] interfaces;
|
||||
// ClassInfo *base; // base class
|
||||
// void *destructor;
|
||||
// void *invariant; // class invariant
|
||||
// uint flags;
|
||||
// void *deallocator;
|
||||
// OffsetTypeInfo[] offTi;
|
||||
// void *defaultConstructor;
|
||||
// }
|
||||
|
||||
if (cd->llvmClassZ)
|
||||
return;
|
||||
|
||||
Logger::println("CLASS INFO DEFINITION: %s", cd->toChars());
|
||||
LOG_SCOPE;
|
||||
assert(cd->llvmClass);
|
||||
|
||||
// holds the list of initializers for llvm
|
||||
std::vector<llvm::Constant*> inits;
|
||||
|
||||
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
|
||||
DtoConstInitClass(cinfo);
|
||||
assert(cinfo->llvmInitZ);
|
||||
|
||||
llvm::Constant* c;
|
||||
|
||||
// own vtable
|
||||
c = cinfo->llvmInitZ->getOperand(0);
|
||||
assert(c);
|
||||
inits.push_back(c);
|
||||
|
||||
// monitor
|
||||
// TODO no monitors yet
|
||||
|
||||
// initializer
|
||||
c = cinfo->llvmInitZ->getOperand(1);
|
||||
inits.push_back(c);
|
||||
|
||||
// class name
|
||||
// from dmd
|
||||
char *name = cd->ident->toChars();
|
||||
size_t namelen = strlen(name);
|
||||
if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
|
||||
{
|
||||
name = cd->toPrettyChars();
|
||||
namelen = strlen(name);
|
||||
}
|
||||
c = DtoConstString(name);
|
||||
inits.push_back(c);
|
||||
|
||||
// vtbl array
|
||||
c = cinfo->llvmInitZ->getOperand(3);
|
||||
inits.push_back(c);
|
||||
|
||||
// interfaces array
|
||||
c = cinfo->llvmInitZ->getOperand(4);
|
||||
inits.push_back(c);
|
||||
|
||||
// base classinfo
|
||||
c = cinfo->llvmInitZ->getOperand(5);
|
||||
inits.push_back(c);
|
||||
|
||||
// destructor
|
||||
c = cinfo->llvmInitZ->getOperand(6);
|
||||
inits.push_back(c);
|
||||
|
||||
// invariant
|
||||
c = cinfo->llvmInitZ->getOperand(7);
|
||||
inits.push_back(c);
|
||||
|
||||
// flags
|
||||
c = cinfo->llvmInitZ->getOperand(8);
|
||||
inits.push_back(c);
|
||||
|
||||
// allocator
|
||||
c = cinfo->llvmInitZ->getOperand(9);
|
||||
inits.push_back(c);
|
||||
|
||||
// offset typeinfo
|
||||
c = cinfo->llvmInitZ->getOperand(10);
|
||||
inits.push_back(c);
|
||||
|
||||
// default constructor
|
||||
c = cinfo->llvmInitZ->getOperand(11);
|
||||
inits.push_back(c);
|
||||
|
||||
/*size_t n = inits.size();
|
||||
for (size_t i=0; i<n; ++i)
|
||||
{
|
||||
Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n';
|
||||
}*/
|
||||
|
||||
// build the initializer
|
||||
const llvm::StructType* st = isaStruct(cinfo->llvmInitZ->getType());
|
||||
llvm::Constant* finalinit = llvm::ConstantStruct::get(st, inits);
|
||||
//Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n';
|
||||
|
||||
cd->llvmClassZ = finalinit;
|
||||
cd->llvmClass->setInitializer(finalinit);
|
||||
}
|
25
gen/classes.h
Normal file
25
gen/classes.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef LLVMDC_GEN_CLASSES_H
|
||||
#define LLVMDC_GEN_CLASSES_H
|
||||
|
||||
/**
|
||||
* Provides the llvm declaration for a class declaration
|
||||
*/
|
||||
void DtoDeclareClass(ClassDeclaration* cd);
|
||||
|
||||
/**
|
||||
* Constructs the constant initializer for a class declaration
|
||||
*/
|
||||
void DtoConstInitClass(ClassDeclaration* cd);
|
||||
|
||||
/**
|
||||
* Provides the llvm definition for a class declaration
|
||||
*/
|
||||
void DtoDefineClass(ClassDeclaration* cd);
|
||||
|
||||
void DtoDeclareClassInfo(ClassDeclaration* cd);
|
||||
void DtoDefineClassInfo(ClassDeclaration* cd);
|
||||
|
||||
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
|
||||
void DtoInitClass(TypeClass* tc, llvm::Value* dst);
|
||||
|
||||
#endif
|
662
gen/functions.cpp
Normal file
662
gen/functions.cpp
Normal file
|
@ -0,0 +1,662 @@
|
|||
#include "gen/llvm.h"
|
||||
|
||||
#include "mtype.h"
|
||||
#include "aggregate.h"
|
||||
#include "init.h"
|
||||
#include "declaration.h"
|
||||
#include "template.h"
|
||||
#include "module.h"
|
||||
#include "statement.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/functions.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/classes.h"
|
||||
|
||||
const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype, bool ismain)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)type;
|
||||
assert(f != 0);
|
||||
|
||||
if (type->llvmType != NULL) {
|
||||
return llvm::cast<llvm::FunctionType>(type->llvmType->get());
|
||||
}
|
||||
|
||||
bool typesafeVararg = false;
|
||||
if (f->linkage == LINKd && f->varargs == 1) {
|
||||
typesafeVararg = true;
|
||||
}
|
||||
|
||||
// return value type
|
||||
const llvm::Type* rettype;
|
||||
const llvm::Type* actualRettype;
|
||||
Type* rt = f->next;
|
||||
bool retinptr = false;
|
||||
bool usesthis = false;
|
||||
|
||||
if (ismain) {
|
||||
rettype = llvm::Type::Int32Ty;
|
||||
actualRettype = rettype;
|
||||
}
|
||||
else {
|
||||
assert(rt);
|
||||
if (DtoIsPassedByRef(rt)) {
|
||||
rettype = llvm::PointerType::get(DtoType(rt));
|
||||
actualRettype = llvm::Type::VoidTy;
|
||||
f->llvmRetInPtr = retinptr = true;
|
||||
}
|
||||
else {
|
||||
rettype = DtoType(rt);
|
||||
actualRettype = rettype;
|
||||
}
|
||||
}
|
||||
|
||||
// parameter types
|
||||
std::vector<const llvm::Type*> paramvec;
|
||||
|
||||
if (retinptr) {
|
||||
Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
|
||||
paramvec.push_back(rettype);
|
||||
}
|
||||
|
||||
if (thistype) {
|
||||
paramvec.push_back(thistype);
|
||||
usesthis = true;
|
||||
}
|
||||
|
||||
if (typesafeVararg) {
|
||||
ClassDeclaration* ti = Type::typeinfo;
|
||||
ti->toObjFile();
|
||||
DtoConstInitClass(ti);
|
||||
assert(ti->llvmInitZ);
|
||||
std::vector<const llvm::Type*> types;
|
||||
types.push_back(DtoSize_t());
|
||||
types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmInitZ->getType())));
|
||||
const llvm::Type* t1 = llvm::StructType::get(types);
|
||||
paramvec.push_back(llvm::PointerType::get(t1));
|
||||
paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
|
||||
}
|
||||
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
// ensure scalar
|
||||
Type* argT = DtoDType(arg->type);
|
||||
assert(argT);
|
||||
|
||||
if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
|
||||
//assert(arg->vardecl);
|
||||
//arg->vardecl->refparam = true;
|
||||
}
|
||||
else
|
||||
arg->llvmCopy = true;
|
||||
|
||||
const llvm::Type* at = DtoType(argT);
|
||||
if (isaStruct(at)) {
|
||||
Logger::println("struct param");
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (isaArray(at)) {
|
||||
Logger::println("sarray param");
|
||||
assert(argT->ty == Tsarray);
|
||||
//paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (llvm::isa<llvm::OpaqueType>(at)) {
|
||||
Logger::println("opaque param");
|
||||
assert(argT->ty == Tstruct || argT->ty == Tclass);
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else {
|
||||
if (!arg->llvmCopy) {
|
||||
Logger::println("ref param");
|
||||
at = llvm::PointerType::get(at);
|
||||
}
|
||||
else {
|
||||
Logger::println("in param");
|
||||
}
|
||||
paramvec.push_back(at);
|
||||
}
|
||||
}
|
||||
|
||||
// construct function type
|
||||
bool isvararg = !typesafeVararg && f->varargs;
|
||||
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
|
||||
|
||||
f->llvmRetInPtr = retinptr;
|
||||
f->llvmUsesThis = usesthis;
|
||||
|
||||
if (!f->llvmType)
|
||||
f->llvmType = new llvm::PATypeHolder(functype);
|
||||
else
|
||||
assert(functype == f->llvmType->get());
|
||||
|
||||
return functype;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)fdecl->type;
|
||||
assert(f != 0);
|
||||
|
||||
const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
std::vector<const llvm::Type*> args;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
args.push_back(i8pty);
|
||||
}
|
||||
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
args.push_back(i8pty);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false);
|
||||
|
||||
if (!f->llvmType)
|
||||
f->llvmType = new llvm::PATypeHolder(fty);
|
||||
else
|
||||
assert(fty == f->llvmType->get());
|
||||
|
||||
return fty;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
|
||||
{
|
||||
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
||||
return DtoVaFunctionType(fdecl);
|
||||
}
|
||||
|
||||
// type has already been resolved
|
||||
if (fdecl->type->llvmType != 0) {
|
||||
return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get());
|
||||
}
|
||||
|
||||
const llvm::Type* thisty = NULL;
|
||||
if (fdecl->needThis()) {
|
||||
if (AggregateDeclaration* ad = fdecl->isMember()) {
|
||||
Logger::print("isMember = this is: %s\n", ad->type->toChars());
|
||||
thisty = DtoType(ad->type);
|
||||
Logger::cout() << "this llvm type: " << *thisty << '\n';
|
||||
if (isaStruct(thisty) || thisty == gIR->topstruct()->recty.get())
|
||||
thisty = llvm::PointerType::get(thisty);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
else if (fdecl->isNested()) {
|
||||
thisty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
}
|
||||
|
||||
const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, fdecl->isMain());
|
||||
|
||||
return functype;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type);
|
||||
const llvm::FunctionType* fty = DtoVaFunctionType(fdecl);
|
||||
llvm::Constant* fn = 0;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
fn = gIR->module->getOrInsertFunction("llvm.va_start", fty);
|
||||
assert(fn);
|
||||
}
|
||||
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty);
|
||||
assert(fn);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
llvm::Function* func = llvm::dyn_cast<llvm::Function>(fn);
|
||||
assert(func);
|
||||
assert(func->isIntrinsic());
|
||||
fdecl->llvmValue = func;
|
||||
return func;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
if (fdecl->llvmRunTimeHack) {
|
||||
Logger::println("runtime hack func chars: %s", fdecl->toChars());
|
||||
if (!fdecl->llvmValue)
|
||||
fdecl->llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, fdecl->toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
if (fdecl->isUnitTestDeclaration()) {
|
||||
Logger::attention("ignoring unittest declaration: %s", fdecl->toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
bool declareOnly = false;
|
||||
if (fdecl->parent)
|
||||
{
|
||||
if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance())
|
||||
{
|
||||
TemplateDeclaration* tempdecl = tinst->tempdecl;
|
||||
if (tempdecl->llvmInternal == LLVMva_start)
|
||||
{
|
||||
Logger::println("magic va_start found");
|
||||
fdecl->llvmInternal = LLVMva_start;
|
||||
declareOnly = true;
|
||||
}
|
||||
else if (tempdecl->llvmInternal == LLVMva_arg)
|
||||
{
|
||||
Logger::println("magic va_arg found");
|
||||
fdecl->llvmInternal = LLVMva_arg;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fdecl->llvmTouched) return;
|
||||
fdecl->llvmTouched = true;
|
||||
|
||||
if (!fdecl->llvmIRFunc) {
|
||||
fdecl->llvmIRFunc = new IRFunction(fdecl);
|
||||
}
|
||||
|
||||
// mangled name
|
||||
char* mangled_name;
|
||||
if (fdecl->llvmInternal == LLVMintrinsic)
|
||||
mangled_name = fdecl->llvmInternal1;
|
||||
else
|
||||
mangled_name = fdecl->mangle();
|
||||
|
||||
// unit test special handling
|
||||
if (fdecl->isUnitTestDeclaration())
|
||||
{
|
||||
assert(0 && "no unittests yet");
|
||||
/*const llvm::FunctionType* fnty = llvm::FunctionType::get(llvm::Type::VoidTy, std::vector<const llvm::Type*>(), false);
|
||||
// make the function
|
||||
llvm::Function* func = gIR->module->getFunction(mangled_name);
|
||||
if (func == 0)
|
||||
func = new llvm::Function(fnty,llvm::GlobalValue::InternalLinkage,mangled_name,gIR->module);
|
||||
func->setCallingConv(llvm::CallingConv::Fast);
|
||||
fdecl->llvmValue = func;
|
||||
return func;
|
||||
*/
|
||||
}
|
||||
|
||||
if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) {
|
||||
error("intrinsics cannot have function bodies");
|
||||
fatal();
|
||||
}
|
||||
|
||||
llvm::Function* vafunc = 0;
|
||||
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
||||
vafunc = DtoDeclareVaFunction(fdecl);
|
||||
}
|
||||
|
||||
Type* t = DtoDType(fdecl->type);
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
|
||||
// construct function
|
||||
const llvm::FunctionType* functype = DtoFunctionType(fdecl);
|
||||
llvm::Function* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name);
|
||||
if (!func)
|
||||
func = new llvm::Function(functype, DtoLinkage(fdecl->protection, fdecl->storage_class), mangled_name, gIR->module);
|
||||
else
|
||||
assert(func->getFunctionType() == functype);
|
||||
|
||||
// add func to IRFunc
|
||||
fdecl->llvmIRFunc->func = func;
|
||||
|
||||
// calling convention
|
||||
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic)
|
||||
func->setCallingConv(DtoCallingConv(f->linkage));
|
||||
|
||||
// template instances should have weak linkage
|
||||
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic && fdecl->parent && DtoIsTemplateInstance(fdecl->parent))
|
||||
func->setLinkage(llvm::GlobalValue::WeakLinkage);
|
||||
|
||||
fdecl->llvmValue = func;
|
||||
assert(llvm::isa<llvm::FunctionType>(f->llvmType->get()));
|
||||
|
||||
if (fdecl->isMain()) {
|
||||
gIR->mainFunc = func;
|
||||
}
|
||||
|
||||
// name parameters
|
||||
llvm::Function::arg_iterator iarg = func->arg_begin();
|
||||
int k = 0;
|
||||
if (f->llvmRetInPtr) {
|
||||
iarg->setName("retval");
|
||||
f->llvmRetArg = iarg;
|
||||
++iarg;
|
||||
}
|
||||
if (f->llvmUsesThis) {
|
||||
iarg->setName("this");
|
||||
++iarg;
|
||||
}
|
||||
int varargs = -1;
|
||||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
varargs = 0;
|
||||
for (; iarg != func->arg_end(); ++iarg)
|
||||
{
|
||||
Argument* arg = Argument::getNth(f->parameters, k++);
|
||||
//arg->llvmValue = iarg;
|
||||
//Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
|
||||
if (arg && arg->ident != 0) {
|
||||
if (arg->vardecl) {
|
||||
arg->vardecl->llvmValue = iarg;
|
||||
}
|
||||
iarg->setName(arg->ident->toChars());
|
||||
}
|
||||
else if (!arg && varargs >= 0) {
|
||||
if (varargs == 0) {
|
||||
iarg->setName("_arguments");
|
||||
fdecl->llvmArguments = iarg;
|
||||
}
|
||||
else if (varargs == 1) {
|
||||
iarg->setName("_argptr");
|
||||
fdecl->llvmArgPtr = iarg;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
varargs++;
|
||||
}
|
||||
else {
|
||||
iarg->setName("unnamed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!declareOnly)
|
||||
gIR->defineQueue.push_back(fdecl);
|
||||
|
||||
Logger::cout() << "func decl: " << *func << '\n';
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO split this monster up
|
||||
void DtoDefineFunc(FuncDeclaration* fd)
|
||||
{
|
||||
// debug info
|
||||
if (global.params.symdebug) {
|
||||
Module* mo = fd->getModule();
|
||||
if (!mo->llvmCompileUnit) {
|
||||
mo->llvmCompileUnit = DtoDwarfCompileUnit(mo,false);
|
||||
}
|
||||
fd->llvmDwarfSubProgram = DtoDwarfSubProgram(fd, mo->llvmCompileUnit);
|
||||
}
|
||||
|
||||
Type* t = DtoDType(fd->type);
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
|
||||
assert(f->llvmType);
|
||||
llvm::Function* func = fd->llvmIRFunc->func;
|
||||
const llvm::FunctionType* functype = func->getFunctionType();
|
||||
|
||||
// only members of the current module or template instances maybe be defined
|
||||
if (fd->getModule() == gIR->dmodule || DtoIsTemplateInstance(fd->parent))
|
||||
{
|
||||
fd->llvmDModule = gIR->dmodule;
|
||||
|
||||
// handle static constructor / destructor
|
||||
if (fd->isStaticCtorDeclaration() || fd->isStaticDtorDeclaration()) {
|
||||
const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1);
|
||||
//Logger::cout() << "static ctor type: " << *sctor_type << '\n';
|
||||
|
||||
llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(fd->llvmValue);
|
||||
//Logger::cout() << "static ctor func: " << *sctor_func << '\n';
|
||||
|
||||
llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1);
|
||||
|
||||
//Logger::cout() << "static ctor init: " << *sctor_init << '\n';
|
||||
|
||||
// output the llvm.global_ctors array
|
||||
const char* varname = fd->isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array";
|
||||
llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module);
|
||||
}
|
||||
|
||||
// function definition
|
||||
if (fd->fbody != 0)
|
||||
{
|
||||
Logger::println("Doing function body for: %s", fd->toChars());
|
||||
assert(fd->llvmIRFunc);
|
||||
gIR->functions.push_back(fd->llvmIRFunc);
|
||||
|
||||
// this handling
|
||||
if (f->llvmUsesThis) {
|
||||
Logger::println("uses this");
|
||||
if (f->llvmRetInPtr)
|
||||
fd->llvmThisVar = ++func->arg_begin();
|
||||
else
|
||||
fd->llvmThisVar = func->arg_begin();
|
||||
assert(fd->llvmThisVar != 0);
|
||||
}
|
||||
|
||||
if (fd->isMain())
|
||||
gIR->emitMain = true;
|
||||
|
||||
llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func);
|
||||
llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func);
|
||||
|
||||
//assert(gIR->scopes.empty());
|
||||
gIR->scopes.push_back(IRScope(beginbb, endbb));
|
||||
|
||||
// create alloca point
|
||||
f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
|
||||
gIR->func()->allocapoint = f->llvmAllocaPoint;
|
||||
|
||||
// give arguments storage
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
if (arg && arg->vardecl) {
|
||||
VarDeclaration* vd = arg->vardecl;
|
||||
if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))
|
||||
continue;
|
||||
llvm::Value* a = vd->llvmValue;
|
||||
assert(a);
|
||||
std::string s(a->getName());
|
||||
Logger::println("giving argument '%s' storage", s.c_str());
|
||||
s.append("_storage");
|
||||
llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint);
|
||||
gIR->ir->CreateStore(a,v);
|
||||
vd->llvmValue = v;
|
||||
}
|
||||
else {
|
||||
Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// debug info
|
||||
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
||||
|
||||
llvm::Value* parentNested = NULL;
|
||||
if (FuncDeclaration* fd2 = fd->toParent()->isFuncDeclaration()) {
|
||||
parentNested = fd2->llvmNested;
|
||||
}
|
||||
|
||||
// construct nested variables struct
|
||||
if (!fd->llvmNestedVars.empty() || parentNested) {
|
||||
std::vector<const llvm::Type*> nestTypes;
|
||||
int j = 0;
|
||||
if (parentNested) {
|
||||
nestTypes.push_back(parentNested->getType());
|
||||
j++;
|
||||
}
|
||||
for (std::set<VarDeclaration*>::iterator i=fd->llvmNestedVars.begin(); i!=fd->llvmNestedVars.end(); ++i) {
|
||||
VarDeclaration* vd = *i;
|
||||
vd->llvmNestedIndex = j++;
|
||||
if (vd->isParameter()) {
|
||||
assert(vd->llvmValue);
|
||||
nestTypes.push_back(vd->llvmValue->getType());
|
||||
}
|
||||
else {
|
||||
nestTypes.push_back(DtoType(vd->type));
|
||||
}
|
||||
}
|
||||
const llvm::StructType* nestSType = llvm::StructType::get(nestTypes);
|
||||
Logger::cout() << "nested var struct has type:" << '\n' << *nestSType;
|
||||
fd->llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint);
|
||||
if (parentNested) {
|
||||
assert(fd->llvmThisVar);
|
||||
llvm::Value* ptr = gIR->ir->CreateBitCast(fd->llvmThisVar, parentNested->getType(), "tmp");
|
||||
gIR->ir->CreateStore(ptr, DtoGEPi(fd->llvmNested, 0,0, "tmp"));
|
||||
}
|
||||
for (std::set<VarDeclaration*>::iterator i=fd->llvmNestedVars.begin(); i!=fd->llvmNestedVars.end(); ++i) {
|
||||
VarDeclaration* vd = *i;
|
||||
if (vd->isParameter()) {
|
||||
gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(fd->llvmNested, 0, vd->llvmNestedIndex, "tmp"));
|
||||
vd->llvmValue = fd->llvmNested;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy _argptr to a memory location
|
||||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
{
|
||||
llvm::Value* argptrmem = new llvm::AllocaInst(fd->llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint());
|
||||
new llvm::StoreInst(fd->llvmArgPtr, argptrmem, gIR->scopebb());
|
||||
fd->llvmArgPtr = argptrmem;
|
||||
}
|
||||
|
||||
// output function body
|
||||
fd->fbody->toIR(gIR);
|
||||
|
||||
// llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
|
||||
// in automatically, so we do it here.
|
||||
if (!fd->isMain()) {
|
||||
if (!gIR->scopereturned()) {
|
||||
// pass the previous block into this block
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(fd);
|
||||
if (func->getReturnType() == llvm::Type::VoidTy) {
|
||||
new llvm::ReturnInst(gIR->scopebb());
|
||||
}
|
||||
else {
|
||||
new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// erase alloca point
|
||||
f->llvmAllocaPoint->eraseFromParent();
|
||||
f->llvmAllocaPoint = 0;
|
||||
gIR->func()->allocapoint = 0;
|
||||
|
||||
gIR->scopes.pop_back();
|
||||
|
||||
// get rid of the endentry block, it's never used
|
||||
assert(!func->getBasicBlockList().empty());
|
||||
func->getBasicBlockList().pop_back();
|
||||
|
||||
// if the last block is empty now, it must be unreachable or it's a bug somewhere else
|
||||
// would be nice to figure out how to assert that this is correct
|
||||
llvm::BasicBlock* lastbb = &func->getBasicBlockList().back();
|
||||
if (lastbb->empty()) {
|
||||
if (lastbb->getNumUses() == 0)
|
||||
lastbb->eraseFromParent();
|
||||
else {
|
||||
new llvm::UnreachableInst(lastbb);
|
||||
/*if (func->getReturnType() == llvm::Type::VoidTy) {
|
||||
new llvm::ReturnInst(lastbb);
|
||||
}
|
||||
else {
|
||||
new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
gIR->functions.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoMain()
|
||||
{
|
||||
// emit main function llvm style
|
||||
// int main(int argc, char**argv, char**env);
|
||||
|
||||
assert(gIR != 0);
|
||||
IRState& ir = *gIR;
|
||||
|
||||
assert(ir.emitMain && ir.mainFunc);
|
||||
|
||||
// parameter types
|
||||
std::vector<const llvm::Type*> pvec;
|
||||
pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty);
|
||||
const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
|
||||
pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
|
||||
const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty;
|
||||
|
||||
llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false);
|
||||
llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module);
|
||||
|
||||
llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func);
|
||||
|
||||
// call static ctors
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors");
|
||||
llvm::Instruction* apt = new llvm::CallInst(fn,"",bb);
|
||||
|
||||
// call user main function
|
||||
const llvm::FunctionType* mainty = ir.mainFunc->getFunctionType();
|
||||
llvm::CallInst* call;
|
||||
if (mainty->getNumParams() > 0)
|
||||
{
|
||||
// main with arguments
|
||||
assert(mainty->getNumParams() == 1);
|
||||
std::vector<llvm::Value*> args;
|
||||
llvm::Function* mfn = LLVM_D_GetRuntimeFunction(ir.module,"_d_main_args");
|
||||
|
||||
llvm::Function::arg_iterator argi = func->arg_begin();
|
||||
args.push_back(argi++);
|
||||
args.push_back(argi++);
|
||||
|
||||
const llvm::Type* at = mainty->getParamType(0)->getContainedType(0);
|
||||
llvm::Value* arr = new llvm::AllocaInst(at->getContainedType(1)->getContainedType(0), func->arg_begin(), "argstorage", apt);
|
||||
llvm::Value* a = new llvm::AllocaInst(at, "argarray", apt);
|
||||
llvm::Value* ptr = DtoGEPi(a,0,0,"tmp",bb);
|
||||
llvm::Value* v = args[0];
|
||||
if (v->getType() != DtoSize_t())
|
||||
v = new llvm::ZExtInst(v, DtoSize_t(), "tmp", bb);
|
||||
new llvm::StoreInst(v,ptr,bb);
|
||||
ptr = DtoGEPi(a,0,1,"tmp",bb);
|
||||
new llvm::StoreInst(arr,ptr,bb);
|
||||
args.push_back(a);
|
||||
new llvm::CallInst(mfn, args.begin(), args.end(), "", bb);
|
||||
call = new llvm::CallInst(ir.mainFunc,a,"ret",bb);
|
||||
}
|
||||
else
|
||||
{
|
||||
// main with no arguments
|
||||
call = new llvm::CallInst(ir.mainFunc,"ret",bb);
|
||||
}
|
||||
call->setCallingConv(ir.mainFunc->getCallingConv());
|
||||
|
||||
// call static dtors
|
||||
fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors");
|
||||
new llvm::CallInst(fn,"",bb);
|
||||
|
||||
// return
|
||||
new llvm::ReturnInst(call,bb);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
12
gen/functions.h
Normal file
12
gen/functions.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef LLVMDC_GEN_FUNCTIONS_H
|
||||
#define LLVMDC_GEN_FUNCTIONS_H
|
||||
|
||||
const llvm::FunctionType* DtoFunctionType(Type* t, const llvm::Type* thistype, bool ismain = false);
|
||||
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl);
|
||||
|
||||
void DtoDeclareFunction(FuncDeclaration* fdecl);
|
||||
void DtoDefineFunc(FuncDeclaration* fd);
|
||||
|
||||
void DtoMain();
|
||||
|
||||
#endif
|
|
@ -40,7 +40,7 @@ IRState::IRState()
|
|||
ir.state = this;
|
||||
}
|
||||
|
||||
IRFunction& IRState::func()
|
||||
IRFunction* IRState::func()
|
||||
{
|
||||
assert(!functions.empty() && "Function stack is empty!");
|
||||
return functions.back();
|
||||
|
@ -49,22 +49,22 @@ IRFunction& IRState::func()
|
|||
llvm::Function* IRState::topfunc()
|
||||
{
|
||||
assert(!functions.empty() && "Function stack is empty!");
|
||||
return functions.back().func;
|
||||
return functions.back()->func;
|
||||
}
|
||||
|
||||
TypeFunction* IRState::topfunctype()
|
||||
{
|
||||
assert(!functions.empty() && "Function stack is empty!");
|
||||
return functions.back().type;
|
||||
return functions.back()->type;
|
||||
}
|
||||
|
||||
llvm::Instruction* IRState::topallocapoint()
|
||||
{
|
||||
assert(!functions.empty() && "AllocaPoint stack is empty!");
|
||||
return functions.back().allocapoint;
|
||||
return functions.back()->allocapoint;
|
||||
}
|
||||
|
||||
IRStruct& IRState::topstruct()
|
||||
IRStruct* IRState::topstruct()
|
||||
{
|
||||
assert(!structs.empty() && "Struct vector is empty!");
|
||||
return structs.back();
|
||||
|
@ -109,14 +109,16 @@ IRStruct::IRStruct()
|
|||
: recty(llvm::OpaqueType::get())
|
||||
{
|
||||
type = 0;
|
||||
queueFuncs = true;
|
||||
defined = false;
|
||||
constinited = false;
|
||||
}
|
||||
|
||||
IRStruct::IRStruct(Type* t)
|
||||
: recty(llvm::OpaqueType::get())
|
||||
{
|
||||
type = t;
|
||||
queueFuncs = true;
|
||||
defined = false;
|
||||
constinited = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -153,6 +155,7 @@ IRFunction::IRFunction(FuncDeclaration* fd)
|
|||
func = NULL;
|
||||
allocapoint = NULL;
|
||||
finallyretval = NULL;
|
||||
defined = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -169,3 +172,11 @@ IRExp::IRExp(Expression* l, Expression* r, DValue* val)
|
|||
e2 = r;
|
||||
v = val;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IRGlobal::IRGlobal(VarDeclaration* v) :
|
||||
type(llvm::OpaqueType::get())
|
||||
{
|
||||
var = v;
|
||||
}
|
||||
|
|
|
@ -39,19 +39,20 @@ struct IRScope
|
|||
};
|
||||
|
||||
// represents a struct or class
|
||||
struct IRStruct
|
||||
struct IRStruct : Object
|
||||
{
|
||||
struct Offset
|
||||
{
|
||||
VarDeclaration* var;
|
||||
const llvm::Type* type;
|
||||
llvm::Constant* init;
|
||||
|
||||
Offset(VarDeclaration* v, llvm::Constant* i)
|
||||
: var(v), init(i) {}
|
||||
Offset(VarDeclaration* v, const llvm::Type* ty)
|
||||
: var(v), type(ty), init(NULL) {}
|
||||
};
|
||||
|
||||
typedef std::vector<FuncDeclaration*> FuncDeclVector;
|
||||
typedef std::multimap<unsigned, Offset> OffsetMap;
|
||||
typedef std::vector<VarDeclaration*> VarDeclVector;
|
||||
|
||||
public:
|
||||
IRStruct();
|
||||
|
@ -59,10 +60,11 @@ public:
|
|||
|
||||
Type* type;
|
||||
llvm::PATypeHolder recty;
|
||||
FuncDeclVector funcs;
|
||||
bool queueFuncs;
|
||||
|
||||
OffsetMap offsets;
|
||||
VarDeclVector defaultFields;
|
||||
|
||||
bool defined;
|
||||
bool constinited;
|
||||
};
|
||||
|
||||
// represents a finally block
|
||||
|
@ -76,7 +78,7 @@ struct IRFinally
|
|||
};
|
||||
|
||||
// represents a function
|
||||
struct IRFunction
|
||||
struct IRFunction : Object
|
||||
{
|
||||
llvm::Function* func;
|
||||
llvm::Instruction* allocapoint;
|
||||
|
@ -88,6 +90,8 @@ struct IRFunction
|
|||
FinallyVec finallys;
|
||||
llvm::Value* finallyretval;
|
||||
|
||||
bool defined;
|
||||
|
||||
IRFunction(FuncDeclaration*);
|
||||
};
|
||||
|
||||
|
@ -106,6 +110,15 @@ struct IRExp
|
|||
IRExp(Expression* l, Expression* r, DValue* val);
|
||||
};
|
||||
|
||||
// represents a global variable
|
||||
struct IRGlobal : Object
|
||||
{
|
||||
VarDeclaration* var;
|
||||
llvm::PATypeHolder type;
|
||||
|
||||
IRGlobal(VarDeclaration* v);
|
||||
};
|
||||
|
||||
// represents the module
|
||||
struct IRState
|
||||
{
|
||||
|
@ -116,18 +129,18 @@ struct IRState
|
|||
llvm::Module* module;
|
||||
|
||||
// functions
|
||||
typedef std::vector<IRFunction> FunctionVector;
|
||||
typedef std::vector<IRFunction*> FunctionVector;
|
||||
FunctionVector functions;
|
||||
IRFunction& func();
|
||||
IRFunction* func();
|
||||
|
||||
llvm::Function* topfunc();
|
||||
TypeFunction* topfunctype();
|
||||
llvm::Instruction* topallocapoint();
|
||||
|
||||
// structs
|
||||
typedef std::vector<IRStruct> StructVector;
|
||||
typedef std::vector<IRStruct*> StructVector;
|
||||
StructVector structs;
|
||||
IRStruct& topstruct();
|
||||
IRStruct* topstruct();
|
||||
|
||||
// classes TODO move into IRClass
|
||||
typedef std::vector<ClassDeclaration*> ClassDeclVec;
|
||||
|
@ -163,9 +176,11 @@ struct IRState
|
|||
// builder helper
|
||||
IRBuilderHelper ir;
|
||||
|
||||
// functions queued for lazy definition
|
||||
typedef std::vector<FuncDeclaration*> FuncDeclVector;
|
||||
FuncDeclVector funcQueue;
|
||||
typedef std::vector<Dsymbol*> DsymbolVector;
|
||||
// dsymbols that need constant initializers constructed
|
||||
DsymbolVector constInitQueue;
|
||||
// dsymbols that need definitions (symbols in current module)
|
||||
DsymbolVector defineQueue;
|
||||
};
|
||||
|
||||
#endif // LLVMDC_GEN_IRSTATE_H
|
||||
|
|
|
@ -71,9 +71,9 @@ void ReturnStatement::toIR(IRState* p)
|
|||
if (!e->inPlace())
|
||||
DtoAssign(rvar, e);
|
||||
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
IRFunction::FinallyVec& fin = p->func()->finallys;
|
||||
if (fin.empty()) {
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||
new llvm::ReturnInst(p->scopebb());
|
||||
}
|
||||
else {
|
||||
|
@ -87,15 +87,15 @@ void ReturnStatement::toIR(IRState* p)
|
|||
delete e;
|
||||
Logger::cout() << "return value is '" <<*v << "'\n";
|
||||
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
IRFunction::FinallyVec& fin = p->func()->finallys;
|
||||
if (fin.empty()) {
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||
new llvm::ReturnInst(v, p->scopebb());
|
||||
}
|
||||
else {
|
||||
if (!p->func().finallyretval)
|
||||
p->func().finallyretval = new llvm::AllocaInst(v->getType(),"tmpreturn",p->topallocapoint());
|
||||
llvm::Value* rettmp = p->func().finallyretval;
|
||||
if (!p->func()->finallyretval)
|
||||
p->func()->finallyretval = new llvm::AllocaInst(v->getType(),"tmpreturn",p->topallocapoint());
|
||||
llvm::Value* rettmp = p->func()->finallyretval;
|
||||
new llvm::StoreInst(v,rettmp,p->scopebb());
|
||||
new llvm::BranchInst(fin.back().retbb, p->scopebb());
|
||||
}
|
||||
|
@ -104,9 +104,9 @@ void ReturnStatement::toIR(IRState* p)
|
|||
else
|
||||
{
|
||||
if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) {
|
||||
IRFunction::FinallyVec& fin = p->func().finallys;
|
||||
IRFunction::FinallyVec& fin = p->func()->finallys;
|
||||
if (fin.empty()) {
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||
new llvm::ReturnInst(p->scopebb());
|
||||
}
|
||||
else {
|
||||
|
@ -420,8 +420,8 @@ void TryFinallyStatement::toIR(IRState* p)
|
|||
|
||||
// do the try block
|
||||
p->scope() = IRScope(trybb,finallybb);
|
||||
gIR->func().finallys.push_back(IRFinally(finallybb,finallyretbb));
|
||||
IRFinally& fin = p->func().finallys.back();
|
||||
gIR->func()->finallys.push_back(IRFinally(finallybb,finallyretbb));
|
||||
IRFinally& fin = p->func()->finallys.back();
|
||||
|
||||
assert(body);
|
||||
body->toIR(p);
|
||||
|
@ -446,22 +446,22 @@ void TryFinallyStatement::toIR(IRState* p)
|
|||
finalbody->toIR(p); // hope this will work, otherwise it's time it gets fixed
|
||||
|
||||
// terminate finally (return path)
|
||||
size_t nfin = p->func().finallys.size();
|
||||
size_t nfin = p->func()->finallys.size();
|
||||
if (nfin > 1) {
|
||||
IRFinally& ofin = p->func().finallys[nfin-2];
|
||||
IRFinally& ofin = p->func()->finallys[nfin-2];
|
||||
p->ir->CreateBr(ofin.retbb);
|
||||
}
|
||||
// no outer
|
||||
else
|
||||
{
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func().decl);
|
||||
llvm::Value* retval = p->func().finallyretval;
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
|
||||
llvm::Value* retval = p->func()->finallyretval;
|
||||
if (retval) {
|
||||
retval = p->ir->CreateLoad(retval,"tmp");
|
||||
p->ir->CreateRet(retval);
|
||||
}
|
||||
else {
|
||||
FuncDeclaration* fd = p->func().decl;
|
||||
FuncDeclaration* fd = p->func()->decl;
|
||||
if (fd->isMain()) {
|
||||
assert(fd->type->next->ty == Tvoid);
|
||||
p->ir->CreateRet(DtoConstInt(0));
|
||||
|
@ -473,7 +473,7 @@ void TryFinallyStatement::toIR(IRState* p)
|
|||
}
|
||||
|
||||
// rewrite the scope
|
||||
p->func().finallys.pop_back();
|
||||
p->func()->finallys.pop_back();
|
||||
p->scope() = IRScope(endbb,oldend);
|
||||
}
|
||||
|
||||
|
|
233
gen/structs.cpp
233
gen/structs.cpp
|
@ -78,7 +78,9 @@ llvm::Constant* DtoConstStructInitializer(StructInitializer* si)
|
|||
Logger::println("DtoConstStructInitializer: %s", si->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
const llvm::StructType* structtype = isaStruct(si->ad->llvmType);
|
||||
TypeStruct* ts = (TypeStruct*)si->ad->type;
|
||||
|
||||
const llvm::StructType* structtype = isaStruct(ts->llvmType->get());
|
||||
Logger::cout() << "llvm struct type: " << *structtype << '\n';
|
||||
|
||||
assert(si->value.dim == si->vars.dim);
|
||||
|
@ -160,6 +162,231 @@ llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, un
|
|||
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
||||
return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDeclareStruct(StructDeclaration* sd)
|
||||
{
|
||||
if (sd->llvmTouched) return;
|
||||
sd->llvmTouched = true;
|
||||
|
||||
Logger::println("DtoDeclareStruct(%s)", sd->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
TypeStruct* ts = (TypeStruct*)DtoDType(sd->type);
|
||||
|
||||
IRStruct* irstruct = new IRStruct(ts);
|
||||
sd->llvmIRStruct = irstruct;
|
||||
gIR->structs.push_back(irstruct);
|
||||
|
||||
for (int k=0; k < sd->members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]);
|
||||
dsym->toObjFile();
|
||||
}
|
||||
|
||||
Logger::println("doing struct fields");
|
||||
|
||||
const llvm::StructType* structtype = 0;
|
||||
std::vector<const llvm::Type*> fieldtypes;
|
||||
|
||||
if (irstruct->offsets.empty())
|
||||
{
|
||||
Logger::println("has no fields");
|
||||
fieldtypes.push_back(llvm::Type::Int8Ty);
|
||||
structtype = llvm::StructType::get(fieldtypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::println("has fields");
|
||||
unsigned prevsize = (unsigned)-1;
|
||||
unsigned lastoffset = (unsigned)-1;
|
||||
const llvm::Type* fieldtype = NULL;
|
||||
VarDeclaration* fieldinit = NULL;
|
||||
size_t fieldpad = 0;
|
||||
int idx = 0;
|
||||
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
|
||||
// first iteration
|
||||
if (lastoffset == (unsigned)-1) {
|
||||
lastoffset = i->first;
|
||||
assert(lastoffset == 0);
|
||||
fieldtype = i->second.type;
|
||||
fieldinit = i->second.var;
|
||||
prevsize = gTargetData->getTypeSize(fieldtype);
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
}
|
||||
// colliding offset?
|
||||
else if (lastoffset == i->first) {
|
||||
size_t s = gTargetData->getTypeSize(i->second.type);
|
||||
if (s > prevsize) {
|
||||
fieldpad += s - prevsize;
|
||||
prevsize = s;
|
||||
}
|
||||
sd->llvmHasUnions = true;
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
}
|
||||
// intersecting offset?
|
||||
else if (i->first < (lastoffset + prevsize)) {
|
||||
size_t s = gTargetData->getTypeSize(i->second.type);
|
||||
assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size
|
||||
sd->llvmHasUnions = true;
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s;
|
||||
}
|
||||
// fresh offset
|
||||
else {
|
||||
// commit the field
|
||||
fieldtypes.push_back(fieldtype);
|
||||
irstruct->defaultFields.push_back(fieldinit);
|
||||
if (fieldpad) {
|
||||
fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad));
|
||||
irstruct->defaultFields.push_back(NULL);
|
||||
idx++;
|
||||
}
|
||||
|
||||
idx++;
|
||||
|
||||
// start new
|
||||
lastoffset = i->first;
|
||||
fieldtype = i->second.type;
|
||||
fieldinit = i->second.var;
|
||||
prevsize = gTargetData->getTypeSize(fieldtype);
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
fieldpad = 0;
|
||||
}
|
||||
}
|
||||
fieldtypes.push_back(fieldtype);
|
||||
irstruct->defaultFields.push_back(fieldinit);
|
||||
if (fieldpad) {
|
||||
fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad));
|
||||
irstruct->defaultFields.push_back(NULL);
|
||||
}
|
||||
|
||||
Logger::println("creating struct type");
|
||||
structtype = llvm::StructType::get(fieldtypes);
|
||||
}
|
||||
|
||||
// refine abstract types for stuff like: struct S{S* next;}
|
||||
if (irstruct->recty != 0)
|
||||
{
|
||||
llvm::PATypeHolder& pa = irstruct->recty;
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype);
|
||||
structtype = isaStruct(pa.get());
|
||||
}
|
||||
|
||||
assert(ts->llvmType == 0);
|
||||
ts->llvmType = new llvm::PATypeHolder(structtype);
|
||||
|
||||
if (sd->parent->isModule()) {
|
||||
gIR->module->addTypeName(sd->mangle(),structtype);
|
||||
}
|
||||
|
||||
std::string initname("_D");
|
||||
initname.append(sd->mangle());
|
||||
initname.append("6__initZ");
|
||||
|
||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module);
|
||||
ts->llvmInit = initvar;
|
||||
|
||||
gIR->structs.pop_back();
|
||||
|
||||
gIR->constInitQueue.push_back(sd);
|
||||
if (sd->getModule() == gIR->dmodule)
|
||||
gIR->defineQueue.push_back(sd);
|
||||
|
||||
// declare typeinfo
|
||||
if (sd->getModule() == gIR->dmodule && sd->llvmInternal != LLVMnotypeinfo)
|
||||
sd->type->getTypeInfo(NULL);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoConstInitStruct(StructDeclaration* sd)
|
||||
{
|
||||
IRStruct* irstruct = sd->llvmIRStruct;
|
||||
if (irstruct->constinited) return;
|
||||
irstruct->constinited = true;
|
||||
|
||||
Logger::println("DtoConstInitStruct(%s)", sd->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
gIR->structs.push_back(irstruct);
|
||||
|
||||
// make sure each offset knows its default initializer
|
||||
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i)
|
||||
{
|
||||
IRStruct::Offset* so = &i->second;
|
||||
llvm::Constant* finit = DtoConstFieldInitializer(so->var->type, so->var->init);
|
||||
so->init = finit;
|
||||
so->var->llvmConstInit = finit;
|
||||
}
|
||||
|
||||
const llvm::StructType* structtype = isaStruct(sd->type->llvmType->get());
|
||||
|
||||
// go through the field inits and build the default initializer
|
||||
std::vector<llvm::Constant*> fieldinits_ll;
|
||||
size_t nfi = irstruct->defaultFields.size();
|
||||
for (size_t i=0; i<nfi; ++i) {
|
||||
llvm::Constant* c;
|
||||
if (irstruct->defaultFields[i] != NULL) {
|
||||
c = irstruct->defaultFields[i]->llvmConstInit;
|
||||
assert(c);
|
||||
}
|
||||
else {
|
||||
const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i));
|
||||
std::vector<llvm::Constant*> vals(arrty->getNumElements(), llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
|
||||
c = llvm::ConstantArray::get(arrty, vals);
|
||||
}
|
||||
fieldinits_ll.push_back(c);
|
||||
}
|
||||
|
||||
// generate the union mapper
|
||||
sd->llvmUnion = new DUnion; // uses gIR->topstruct()
|
||||
|
||||
// always generate the constant initalizer
|
||||
if (!sd->zeroInit) {
|
||||
Logger::println("Not zero initialized");
|
||||
//assert(tk == gIR->gIR->topstruct()().size());
|
||||
#ifndef LLVMD_NO_LOGGER
|
||||
Logger::cout() << "struct type: " << *structtype << '\n';
|
||||
for (size_t k=0; k<fieldinits_ll.size(); ++k) {
|
||||
Logger::cout() << "Type:" << '\n';
|
||||
Logger::cout() << *fieldinits_ll[k]->getType() << '\n';
|
||||
Logger::cout() << "Value:" << '\n';
|
||||
Logger::cout() << *fieldinits_ll[k] << '\n';
|
||||
}
|
||||
Logger::cout() << "Initializer printed" << '\n';
|
||||
#endif
|
||||
sd->llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits_ll);
|
||||
}
|
||||
else {
|
||||
Logger::println("Zero initialized");
|
||||
sd->llvmInitZ = llvm::ConstantAggregateZero::get(structtype);
|
||||
}
|
||||
|
||||
gIR->structs.pop_back();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDefineStruct(StructDeclaration* sd)
|
||||
{
|
||||
IRStruct* irstruct = sd->llvmIRStruct;
|
||||
if (irstruct->defined) return;
|
||||
irstruct->defined = true;
|
||||
|
||||
DtoConstInitStruct(sd);
|
||||
|
||||
Logger::println("DtoDefineStruct(%s)", sd->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
assert(sd->type->ty == Tstruct);
|
||||
TypeStruct* ts = (TypeStruct*)sd->type;
|
||||
ts->llvmInit->setInitializer(sd->llvmInitZ);
|
||||
|
||||
sd->llvmDModule = gIR->dmodule;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////// D UNION HELPER CLASS ////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -167,9 +394,9 @@ llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, un
|
|||
DUnion::DUnion()
|
||||
{
|
||||
DUnionField* f = NULL;
|
||||
IRStruct& topstruct = gIR->topstruct();
|
||||
IRStruct* topstruct = gIR->topstruct();
|
||||
bool unions = false;
|
||||
for (IRStruct::OffsetMap::iterator i=topstruct.offsets.begin(); i!=topstruct.offsets.end(); ++i)
|
||||
for (IRStruct::OffsetMap::iterator i=topstruct->offsets.begin(); i!=topstruct->offsets.end(); ++i)
|
||||
{
|
||||
unsigned o = i->first;
|
||||
IRStruct::Offset* so = &i->second;
|
||||
|
|
|
@ -2,10 +2,29 @@
|
|||
#define LLVMD_GEN_STRUCTS_H
|
||||
|
||||
struct StructInitializer;
|
||||
|
||||
const llvm::Type* DtoStructType(Type* t);
|
||||
|
||||
llvm::Value* DtoStructZeroInit(llvm::Value* v);
|
||||
llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src);
|
||||
|
||||
llvm::Constant* DtoConstStructInitializer(StructInitializer* si);
|
||||
|
||||
/**
|
||||
* Provides the llvm declaration for a struct
|
||||
*/
|
||||
void DtoDeclareStruct(StructDeclaration* sd);
|
||||
|
||||
/**
|
||||
* Constructs the constant default initializer a struct
|
||||
*/
|
||||
void DtoConstInitStruct(StructDeclaration* sd);
|
||||
|
||||
/**
|
||||
* Provides the llvm definition for a struct
|
||||
*/
|
||||
void DtoDefineStruct(StructDeclaration* sd);
|
||||
|
||||
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs);
|
||||
|
||||
struct DUnionField
|
||||
|
|
48
gen/toir.cpp
48
gen/toir.cpp
|
@ -26,6 +26,7 @@
|
|||
#include "gen/runtime.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/structs.h"
|
||||
#include "gen/classes.h"
|
||||
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
|
@ -52,7 +53,7 @@ DValue* DeclarationExp::toElem(IRState* p)
|
|||
// referenced by nested delegate?
|
||||
if (vd->nestedref) {
|
||||
Logger::println("has nestedref set");
|
||||
vd->llvmValue = p->func().decl->llvmNested;
|
||||
vd->llvmValue = p->func()->decl->llvmNested;
|
||||
assert(vd->llvmValue);
|
||||
assert(vd->llvmNestedIndex >= 0);
|
||||
}
|
||||
|
@ -119,7 +120,7 @@ DValue* VarExp::toElem(IRState* p)
|
|||
{
|
||||
Logger::println("Id::_arguments");
|
||||
if (!vd->llvmValue)
|
||||
vd->llvmValue = p->func().decl->llvmArguments;
|
||||
vd->llvmValue = p->func()->decl->llvmArguments;
|
||||
assert(vd->llvmValue);
|
||||
return new DVarValue(vd, vd->llvmValue, true);
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ DValue* VarExp::toElem(IRState* p)
|
|||
{
|
||||
Logger::println("Id::_argptr");
|
||||
if (!vd->llvmValue)
|
||||
vd->llvmValue = p->func().decl->llvmArgPtr;
|
||||
vd->llvmValue = p->func()->decl->llvmArgPtr;
|
||||
assert(vd->llvmValue);
|
||||
return new DVarValue(vd, vd->llvmValue, true);
|
||||
}
|
||||
|
@ -154,6 +155,13 @@ DValue* VarExp::toElem(IRState* p)
|
|||
m = tid->llvmValue;
|
||||
return new DVarValue(vd, m, true);
|
||||
}
|
||||
// classinfo
|
||||
else if (ClassInfoDeclaration* cid = vd->isClassInfoDeclaration())
|
||||
{
|
||||
Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars());
|
||||
assert(cid->cd->llvmClass);
|
||||
return new DVarValue(vd, cid->cd->llvmClass, true);
|
||||
}
|
||||
// nested variable
|
||||
else if (vd->nestedref) {
|
||||
Logger::println("nested variable");
|
||||
|
@ -165,7 +173,7 @@ DValue* VarExp::toElem(IRState* p)
|
|||
if (!vd->llvmValue) {
|
||||
// TODO: determine this properly
|
||||
// this happens when the DMD frontend generates by pointer wrappers for struct opEquals(S) and opCmp(S)
|
||||
vd->llvmValue = &p->func().func->getArgumentList().back();
|
||||
vd->llvmValue = &p->func()->func->getArgumentList().back();
|
||||
}
|
||||
if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa<llvm::AllocaInst>(vd->llvmValue)) {
|
||||
return new DVarValue(vd, vd->llvmValue, true);
|
||||
|
@ -177,9 +185,11 @@ DValue* VarExp::toElem(IRState* p)
|
|||
}
|
||||
else {
|
||||
// take care of forward references of global variables
|
||||
if (!vd->llvmTouched && (vd->isDataseg() || (vd->storage_class & STCextern))) // !vd->onstack)
|
||||
if (vd->isDataseg() || (vd->storage_class & STCextern)) {
|
||||
vd->toObjFile();
|
||||
if (!vd->llvmValue) {
|
||||
DtoConstInitGlobal(vd);
|
||||
}
|
||||
if (!vd->llvmValue || vd->llvmValue->getType()->isAbstract()) {
|
||||
Logger::println("global variable not resolved :/ %s", vd->toChars());
|
||||
assert(0);
|
||||
}
|
||||
|
@ -224,6 +234,8 @@ llvm::Constant* VarExp::toConstElem(IRState* p)
|
|||
Logger::print("Sym: type=%s\n", sdecltype->toChars());
|
||||
assert(sdecltype->ty == Tstruct);
|
||||
TypeStruct* ts = (TypeStruct*)sdecltype;
|
||||
ts->sym->toObjFile();
|
||||
DtoConstInitStruct(ts->sym);
|
||||
assert(ts->sym->llvmInitZ);
|
||||
return ts->sym->llvmInitZ;
|
||||
}
|
||||
|
@ -1220,7 +1232,7 @@ DValue* CallExp::toElem(IRState* p)
|
|||
// nested call
|
||||
else if (dfn && dfn->func && dfn->func->isNested()) {
|
||||
Logger::println("Nested Call");
|
||||
llvm::Value* contextptr = p->func().decl->llvmNested;
|
||||
llvm::Value* contextptr = p->func()->decl->llvmNested;
|
||||
assert(contextptr);
|
||||
llargs[j] = p->ir->CreateBitCast(contextptr, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
|
||||
++j;
|
||||
|
@ -1330,6 +1342,9 @@ DValue* CallExp::toElem(IRState* p)
|
|||
else if (dfn && dfn->cc != (unsigned)-1) {
|
||||
call->setCallingConv(dfn->cc);
|
||||
}
|
||||
else if (llvm::isa<llvm::LoadInst>(funcval)) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
|
||||
return new DImValue(type, retllval, isInPlace);
|
||||
}
|
||||
|
@ -1445,9 +1460,8 @@ DValue* AddrExp::toElem(IRState* p)
|
|||
DValue* v = e1->toElem(p);
|
||||
if (v->isField())
|
||||
return v;
|
||||
if (DFuncValue* fv = v->isFunc())
|
||||
{
|
||||
Logger::println("FuncDeclaration");
|
||||
else if (DFuncValue* fv = v->isFunc()) {
|
||||
//Logger::println("FuncDeclaration");
|
||||
FuncDeclaration* fd = fv->func;
|
||||
assert(fd);
|
||||
if (fd->llvmValue == 0)
|
||||
|
@ -1562,7 +1576,7 @@ DValue* ThisExp::toElem(IRState* p)
|
|||
LOG_SCOPE;
|
||||
|
||||
if (VarDeclaration* vd = var->isVarDeclaration()) {
|
||||
llvm::Value* v = p->func().decl->llvmThisVar;
|
||||
llvm::Value* v = p->func()->decl->llvmThisVar;
|
||||
if (llvm::isa<llvm::AllocaInst>(v))
|
||||
v = new llvm::LoadInst(v, "tmp", p->scopebb());
|
||||
return new DThisValue(vd, v);
|
||||
|
@ -2023,7 +2037,9 @@ DValue* NewExp::toElem(IRState* p)
|
|||
llvm::Value* a = DtoArgument(fn->getFunctionType()->getParamType(i+1), fnarg, ex);
|
||||
ctorargs.push_back(a);
|
||||
}
|
||||
emem = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb());
|
||||
llvm::CallInst* call = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb());
|
||||
call->setCallingConv(DtoCallingConv(LINKd));
|
||||
emem = call;
|
||||
}
|
||||
}
|
||||
else if (ntype->ty == Tstruct) {
|
||||
|
@ -2505,7 +2521,7 @@ DValue* FuncExp::toElem(IRState* p)
|
|||
|
||||
llvm::Value* context = DtoGEPi(lval,0,0,"tmp",p->scopebb());
|
||||
const llvm::PointerType* pty = isaPointer(context->getType()->getContainedType(0));
|
||||
llvm::Value* llvmNested = p->func().decl->llvmNested;
|
||||
llvm::Value* llvmNested = p->func()->decl->llvmNested;
|
||||
if (llvmNested == NULL) {
|
||||
llvm::Value* nullcontext = llvm::ConstantPointerNull::get(pty);
|
||||
p->ir->CreateStore(nullcontext, context);
|
||||
|
@ -2539,6 +2555,8 @@ DValue* ArrayLiteralExp::toElem(IRState* p)
|
|||
Logger::cout() << "array literal has llvm type: " << *t << '\n';
|
||||
|
||||
llvm::Value* mem = 0;
|
||||
bool inplace_slice = false;
|
||||
|
||||
if (!p->topexp() || p->topexp()->e2 != this) {
|
||||
assert(DtoDType(type)->ty == Tsarray);
|
||||
mem = new llvm::AllocaInst(t,"arrayliteral",p->topallocapoint());
|
||||
|
@ -2548,6 +2566,7 @@ DValue* ArrayLiteralExp::toElem(IRState* p)
|
|||
if (DSliceValue* sv = tlv->isSlice()) {
|
||||
assert(sv->len == 0);
|
||||
mem = sv->ptr;
|
||||
inplace_slice = true;
|
||||
}
|
||||
else {
|
||||
mem = p->topexp()->v->getLVal();
|
||||
|
@ -2556,6 +2575,7 @@ DValue* ArrayLiteralExp::toElem(IRState* p)
|
|||
if (!isaPointer(mem->getType()) ||
|
||||
!isaArray(mem->getType()->getContainedType(0)))
|
||||
{
|
||||
assert(!inplace_slice);
|
||||
assert(ty->ty == Tarray);
|
||||
// we need to give this array literal storage
|
||||
const llvm::ArrayType* arrty = llvm::ArrayType::get(DtoType(ty->next), elements->dim);
|
||||
|
@ -2582,7 +2602,7 @@ DValue* ArrayLiteralExp::toElem(IRState* p)
|
|||
}
|
||||
}
|
||||
|
||||
if (ty->ty == Tsarray)
|
||||
if (ty->ty == Tsarray || (ty->ty == Tarray && inplace_slice))
|
||||
return new DImValue(type, mem, true);
|
||||
else if (ty->ty == Tarray)
|
||||
return new DSliceValue(type, DtoConstSize_t(elements->dim), DtoGEPi(mem,0,0,"tmp"));
|
||||
|
|
636
gen/tollvm.cpp
636
gen/tollvm.cpp
|
@ -14,7 +14,9 @@
|
|||
#include "gen/runtime.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/functions.h"
|
||||
#include "gen/structs.h"
|
||||
#include "gen/classes.h"
|
||||
|
||||
bool DtoIsPassedByRef(Type* type)
|
||||
{
|
||||
|
@ -95,17 +97,16 @@ const llvm::Type* DtoType(Type* t)
|
|||
|
||||
// aggregates
|
||||
case Tstruct: {
|
||||
if (t->llvmType == 0)
|
||||
{
|
||||
if (!t->llvmType || *t->llvmType == NULL) {
|
||||
// recursive or cyclic declaration
|
||||
if (!gIR->structs.empty())
|
||||
{
|
||||
IRStruct* found = 0;
|
||||
for (IRState::StructVector::iterator i=gIR->structs.begin(); i!=gIR->structs.end(); ++i)
|
||||
{
|
||||
if (t == i->type)
|
||||
if (t == (*i)->type)
|
||||
{
|
||||
return i->recty.get();
|
||||
return (*i)->recty.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,21 +116,20 @@ const llvm::Type* DtoType(Type* t)
|
|||
assert(ts->sym);
|
||||
ts->sym->toObjFile();
|
||||
}
|
||||
return t->llvmType;
|
||||
return t->llvmType->get();
|
||||
}
|
||||
|
||||
case Tclass: {
|
||||
if (t->llvmType == 0)
|
||||
{
|
||||
if (!t->llvmType || *t->llvmType == NULL) {
|
||||
// recursive or cyclic declaration
|
||||
if (!gIR->structs.empty())
|
||||
{
|
||||
IRStruct* found = 0;
|
||||
for (IRState::StructVector::iterator i=gIR->structs.begin(); i!=gIR->structs.end(); ++i)
|
||||
{
|
||||
if (t == i->type)
|
||||
if (t == (*i)->type)
|
||||
{
|
||||
return llvm::PointerType::get(i->recty.get());
|
||||
return llvm::PointerType::get((*i)->recty.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,28 +139,28 @@ const llvm::Type* DtoType(Type* t)
|
|||
assert(tc->sym);
|
||||
tc->sym->toObjFile();
|
||||
}
|
||||
return llvm::PointerType::get(t->llvmType);
|
||||
return llvm::PointerType::get(t->llvmType->get());
|
||||
}
|
||||
|
||||
// functions
|
||||
case Tfunction:
|
||||
{
|
||||
if (t->llvmType == 0) {
|
||||
if (!t->llvmType || *t->llvmType == NULL) {
|
||||
return DtoFunctionType(t,NULL);
|
||||
}
|
||||
else {
|
||||
return t->llvmType;
|
||||
return t->llvmType->get();
|
||||
}
|
||||
}
|
||||
|
||||
// delegates
|
||||
case Tdelegate:
|
||||
{
|
||||
if (t->llvmType == 0) {
|
||||
if (!t->llvmType || *t->llvmType == NULL) {
|
||||
return DtoDelegateType(t);
|
||||
}
|
||||
else {
|
||||
return t->llvmType;
|
||||
return t->llvmType->get();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,181 +183,6 @@ const llvm::Type* DtoType(Type* t)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype, bool ismain)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)type;
|
||||
assert(f != 0);
|
||||
|
||||
bool typesafeVararg = false;
|
||||
if (f->linkage == LINKd && f->varargs == 1) {
|
||||
typesafeVararg = true;
|
||||
}
|
||||
|
||||
// return value type
|
||||
const llvm::Type* rettype;
|
||||
const llvm::Type* actualRettype;
|
||||
Type* rt = f->next;
|
||||
bool retinptr = false;
|
||||
bool usesthis = false;
|
||||
|
||||
if (ismain) {
|
||||
rettype = llvm::Type::Int32Ty;
|
||||
actualRettype = rettype;
|
||||
}
|
||||
else {
|
||||
assert(rt);
|
||||
if (DtoIsPassedByRef(rt)) {
|
||||
rettype = llvm::PointerType::get(DtoType(rt));
|
||||
actualRettype = llvm::Type::VoidTy;
|
||||
f->llvmRetInPtr = retinptr = true;
|
||||
}
|
||||
else {
|
||||
rettype = DtoType(rt);
|
||||
actualRettype = rettype;
|
||||
}
|
||||
}
|
||||
|
||||
// parameter types
|
||||
std::vector<const llvm::Type*> paramvec;
|
||||
|
||||
if (retinptr) {
|
||||
Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
|
||||
paramvec.push_back(rettype);
|
||||
}
|
||||
|
||||
if (thistype) {
|
||||
paramvec.push_back(thistype);
|
||||
usesthis = true;
|
||||
}
|
||||
|
||||
if (typesafeVararg) {
|
||||
ClassDeclaration* ti = Type::typeinfo;
|
||||
if (!ti->llvmInitZ)
|
||||
ti->toObjFile();
|
||||
assert(ti->llvmInitZ);
|
||||
std::vector<const llvm::Type*> types;
|
||||
types.push_back(DtoSize_t());
|
||||
types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmInitZ->getType())));
|
||||
const llvm::Type* t1 = llvm::StructType::get(types);
|
||||
paramvec.push_back(llvm::PointerType::get(t1));
|
||||
paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
|
||||
}
|
||||
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
// ensure scalar
|
||||
Type* argT = DtoDType(arg->type);
|
||||
assert(argT);
|
||||
|
||||
if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
|
||||
//assert(arg->vardecl);
|
||||
//arg->vardecl->refparam = true;
|
||||
}
|
||||
else
|
||||
arg->llvmCopy = true;
|
||||
|
||||
const llvm::Type* at = DtoType(argT);
|
||||
if (isaStruct(at)) {
|
||||
Logger::println("struct param");
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (isaArray(at)) {
|
||||
Logger::println("sarray param");
|
||||
assert(argT->ty == Tsarray);
|
||||
//paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else if (llvm::isa<llvm::OpaqueType>(at)) {
|
||||
Logger::println("opaque param");
|
||||
assert(argT->ty == Tstruct || argT->ty == Tclass);
|
||||
paramvec.push_back(llvm::PointerType::get(at));
|
||||
}
|
||||
else {
|
||||
if (!arg->llvmCopy) {
|
||||
Logger::println("ref param");
|
||||
at = llvm::PointerType::get(at);
|
||||
}
|
||||
else {
|
||||
Logger::println("in param");
|
||||
}
|
||||
paramvec.push_back(at);
|
||||
}
|
||||
}
|
||||
|
||||
// construct function type
|
||||
bool isvararg = !typesafeVararg && f->varargs;
|
||||
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
|
||||
|
||||
f->llvmRetInPtr = retinptr;
|
||||
f->llvmUsesThis = usesthis;
|
||||
return functype;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)fdecl->type;
|
||||
assert(f != 0);
|
||||
|
||||
const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
std::vector<const llvm::Type*> args;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
args.push_back(i8pty);
|
||||
}
|
||||
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
args.push_back(i8pty);
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false);
|
||||
f->llvmType = fty;
|
||||
return fty;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
|
||||
{
|
||||
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
||||
return DtoVaFunctionType(fdecl);
|
||||
}
|
||||
|
||||
// type has already been resolved
|
||||
if (fdecl->type->llvmType != 0) {
|
||||
return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType);
|
||||
}
|
||||
|
||||
const llvm::Type* thisty = NULL;
|
||||
if (fdecl->needThis()) {
|
||||
if (AggregateDeclaration* ad = fdecl->isMember()) {
|
||||
Logger::print("isMember = this is: %s\n", ad->type->toChars());
|
||||
thisty = DtoType(ad->type);
|
||||
Logger::cout() << "this llvm type: " << *thisty << '\n';
|
||||
if (isaStruct(thisty) || thisty == gIR->topstruct().recty.get())
|
||||
thisty = llvm::PointerType::get(thisty);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
else if (fdecl->isNested()) {
|
||||
thisty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
}
|
||||
|
||||
const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, fdecl->isMain());
|
||||
fdecl->type->llvmType = functype;
|
||||
return functype;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const llvm::StructType* DtoDelegateType(Type* t)
|
||||
{
|
||||
const llvm::Type* i8ptr = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
|
@ -630,131 +455,6 @@ const llvm::Type* DtoSize_t()
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoMain()
|
||||
{
|
||||
// emit main function llvm style
|
||||
// int main(int argc, char**argv, char**env);
|
||||
|
||||
assert(gIR != 0);
|
||||
IRState& ir = *gIR;
|
||||
|
||||
assert(ir.emitMain && ir.mainFunc);
|
||||
|
||||
// parameter types
|
||||
std::vector<const llvm::Type*> pvec;
|
||||
pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty);
|
||||
const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
|
||||
pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
|
||||
const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty;
|
||||
|
||||
llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false);
|
||||
llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module);
|
||||
|
||||
llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func);
|
||||
|
||||
// call static ctors
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors");
|
||||
llvm::Instruction* apt = new llvm::CallInst(fn,"",bb);
|
||||
|
||||
// call user main function
|
||||
const llvm::FunctionType* mainty = ir.mainFunc->getFunctionType();
|
||||
llvm::CallInst* call;
|
||||
if (mainty->getNumParams() > 0)
|
||||
{
|
||||
// main with arguments
|
||||
assert(mainty->getNumParams() == 1);
|
||||
std::vector<llvm::Value*> args;
|
||||
llvm::Function* mfn = LLVM_D_GetRuntimeFunction(ir.module,"_d_main_args");
|
||||
|
||||
llvm::Function::arg_iterator argi = func->arg_begin();
|
||||
args.push_back(argi++);
|
||||
args.push_back(argi++);
|
||||
|
||||
const llvm::Type* at = mainty->getParamType(0)->getContainedType(0);
|
||||
llvm::Value* arr = new llvm::AllocaInst(at->getContainedType(1)->getContainedType(0), func->arg_begin(), "argstorage", apt);
|
||||
llvm::Value* a = new llvm::AllocaInst(at, "argarray", apt);
|
||||
llvm::Value* ptr = DtoGEPi(a,0,0,"tmp",bb);
|
||||
llvm::Value* v = args[0];
|
||||
if (v->getType() != DtoSize_t())
|
||||
v = new llvm::ZExtInst(v, DtoSize_t(), "tmp", bb);
|
||||
new llvm::StoreInst(v,ptr,bb);
|
||||
ptr = DtoGEPi(a,0,1,"tmp",bb);
|
||||
new llvm::StoreInst(arr,ptr,bb);
|
||||
args.push_back(a);
|
||||
new llvm::CallInst(mfn, args.begin(), args.end(), "", bb);
|
||||
call = new llvm::CallInst(ir.mainFunc,a,"ret",bb);
|
||||
}
|
||||
else
|
||||
{
|
||||
// main with no arguments
|
||||
call = new llvm::CallInst(ir.mainFunc,"ret",bb);
|
||||
}
|
||||
call->setCallingConv(ir.mainFunc->getCallingConv());
|
||||
|
||||
// call static dtors
|
||||
fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors");
|
||||
new llvm::CallInst(fn,"",bb);
|
||||
|
||||
// return
|
||||
new llvm::ReturnInst(call,bb);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
|
||||
{
|
||||
Array* arr = &tc->sym->dtors;
|
||||
for (size_t i=0; i<arr->dim; i++)
|
||||
{
|
||||
FuncDeclaration* fd = (FuncDeclaration*)arr->data[i];
|
||||
assert(fd->llvmValue);
|
||||
new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoInitClass(TypeClass* tc, llvm::Value* dst)
|
||||
{
|
||||
assert(gIR);
|
||||
|
||||
assert(tc->llvmType);
|
||||
uint64_t size_t_size = gTargetData->getTypeSize(DtoSize_t());
|
||||
uint64_t n = gTargetData->getTypeSize(tc->llvmType) - size_t_size;
|
||||
|
||||
// set vtable field
|
||||
llvm::Value* vtblvar = DtoGEPi(dst,0,0,"tmp",gIR->scopebb());
|
||||
assert(tc->sym->llvmVtbl);
|
||||
new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb());
|
||||
|
||||
// copy the static initializer
|
||||
if (n > 0) {
|
||||
assert(tc->llvmInit);
|
||||
assert(dst->getType() == tc->llvmInit->getType());
|
||||
|
||||
llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
|
||||
llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
|
||||
dstarr = DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb());
|
||||
|
||||
llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb());
|
||||
srcarr = DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb());
|
||||
|
||||
llvm::Function* fn = LLVM_DeclareMemCpy32();
|
||||
std::vector<llvm::Value*> llargs;
|
||||
llargs.resize(4);
|
||||
llargs[0] = dstarr;
|
||||
llargs[1] = srcarr;
|
||||
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
|
||||
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
||||
|
||||
new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Constant* DtoConstInitializer(Type* type, Initializer* init)
|
||||
{
|
||||
llvm::Constant* _init = 0; // may return zero
|
||||
|
@ -792,6 +492,54 @@ llvm::Constant* DtoConstInitializer(Type* type, Initializer* init)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Constant* DtoConstFieldInitializer(Type* t, Initializer* init)
|
||||
{
|
||||
Logger::println("DtoConstFieldInitializer");
|
||||
LOG_SCOPE;
|
||||
|
||||
const llvm::Type* _type = DtoType(t);
|
||||
|
||||
llvm::Constant* _init = DtoConstInitializer(t, init);
|
||||
assert(_init);
|
||||
if (_type != _init->getType())
|
||||
{
|
||||
Logger::cout() << "field init is: " << *_init << " type should be " << *_type << '\n';
|
||||
if (t->ty == Tsarray)
|
||||
{
|
||||
const llvm::ArrayType* arrty = isaArray(_type);
|
||||
uint64_t n = arrty->getNumElements();
|
||||
std::vector<llvm::Constant*> vals(n,_init);
|
||||
_init = llvm::ConstantArray::get(arrty, vals);
|
||||
}
|
||||
else if (t->ty == Tarray)
|
||||
{
|
||||
assert(isaStruct(_type));
|
||||
_init = llvm::ConstantAggregateZero::get(_type);
|
||||
}
|
||||
else if (t->ty == Tstruct)
|
||||
{
|
||||
const llvm::StructType* structty = isaStruct(_type);
|
||||
TypeStruct* ts = (TypeStruct*)t;
|
||||
assert(ts);
|
||||
assert(ts->sym);
|
||||
assert(ts->sym->llvmInitZ);
|
||||
_init = ts->sym->llvmInitZ;
|
||||
}
|
||||
else if (t->ty == Tclass)
|
||||
{
|
||||
_init = llvm::Constant::getNullValue(_type);
|
||||
}
|
||||
else {
|
||||
Logger::println("failed for type %s", t->toChars());
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return _init;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DValue* DtoInitializer(Initializer* init)
|
||||
{
|
||||
if (ExpInitializer* ex = init->isExpInitializer())
|
||||
|
@ -858,152 +606,6 @@ llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::stri
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type);
|
||||
const llvm::FunctionType* fty = DtoVaFunctionType(fdecl);
|
||||
llvm::Constant* fn = 0;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
fn = gIR->module->getOrInsertFunction("llvm.va_start", fty);
|
||||
assert(fn);
|
||||
}
|
||||
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
||||
fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty);
|
||||
assert(fn);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
llvm::Function* func = llvm::dyn_cast<llvm::Function>(fn);
|
||||
assert(func);
|
||||
assert(func->isIntrinsic());
|
||||
fdecl->llvmValue = func;
|
||||
return func;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||
{
|
||||
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
||||
return DtoDeclareVaFunction(fdecl);
|
||||
}
|
||||
|
||||
// mangled name
|
||||
char* mangled_name;
|
||||
if (fdecl->llvmInternal == LLVMintrinsic)
|
||||
mangled_name = fdecl->llvmInternal1;
|
||||
else
|
||||
mangled_name = fdecl->mangle();
|
||||
|
||||
// unit test special handling
|
||||
if (fdecl->isUnitTestDeclaration())
|
||||
{
|
||||
assert(0 && "no unittests yet");
|
||||
/*const llvm::FunctionType* fnty = llvm::FunctionType::get(llvm::Type::VoidTy, std::vector<const llvm::Type*>(), false);
|
||||
// make the function
|
||||
llvm::Function* func = gIR->module->getFunction(mangled_name);
|
||||
if (func == 0)
|
||||
func = new llvm::Function(fnty,llvm::GlobalValue::InternalLinkage,mangled_name,gIR->module);
|
||||
func->setCallingConv(llvm::CallingConv::Fast);
|
||||
fdecl->llvmValue = func;
|
||||
return func;
|
||||
*/
|
||||
}
|
||||
|
||||
// regular function
|
||||
TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type);
|
||||
assert(f != 0);
|
||||
|
||||
if (fdecl->llvmValue != 0) {
|
||||
if (!llvm::isa<llvm::Function>(fdecl->llvmValue))
|
||||
{
|
||||
Logger::cout() << *fdecl->llvmValue << '\n';
|
||||
assert(0);
|
||||
}
|
||||
return llvm::cast<llvm::Function>(fdecl->llvmValue);
|
||||
}
|
||||
|
||||
Logger::print("FuncDeclaration::toObjFile(%s): %s\n", fdecl->needThis()?"this":"static",fdecl->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) {
|
||||
error("intrinsics cannot have function bodies");
|
||||
fatal();
|
||||
}
|
||||
|
||||
// construct function
|
||||
const llvm::FunctionType* functype = (f->llvmType == 0) ? DtoFunctionType(fdecl) : llvm::cast<llvm::FunctionType>(f->llvmType);
|
||||
|
||||
// make the function
|
||||
llvm::Function* func = gIR->module->getFunction(mangled_name);
|
||||
if (func == 0) {
|
||||
func = new llvm::Function(functype,DtoLinkage(fdecl->protection, fdecl->storage_class),mangled_name,gIR->module);
|
||||
}
|
||||
|
||||
if (fdecl->llvmInternal != LLVMintrinsic)
|
||||
func->setCallingConv(DtoCallingConv(f->linkage));
|
||||
|
||||
fdecl->llvmValue = func;
|
||||
f->llvmType = functype;
|
||||
assert(llvm::isa<llvm::FunctionType>(f->llvmType));
|
||||
|
||||
if (fdecl->isMain()) {
|
||||
gIR->mainFunc = func;
|
||||
}
|
||||
|
||||
// name parameters
|
||||
llvm::Function::arg_iterator iarg = func->arg_begin();
|
||||
int k = 0;
|
||||
if (f->llvmRetInPtr) {
|
||||
iarg->setName("retval");
|
||||
f->llvmRetArg = iarg;
|
||||
++iarg;
|
||||
}
|
||||
if (f->llvmUsesThis) {
|
||||
iarg->setName("this");
|
||||
++iarg;
|
||||
}
|
||||
int varargs = -1;
|
||||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
varargs = 0;
|
||||
for (; iarg != func->arg_end(); ++iarg)
|
||||
{
|
||||
Argument* arg = Argument::getNth(f->parameters, k++);
|
||||
//arg->llvmValue = iarg;
|
||||
//Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
|
||||
if (arg && arg->ident != 0) {
|
||||
if (arg->vardecl) {
|
||||
arg->vardecl->llvmValue = iarg;
|
||||
}
|
||||
iarg->setName(arg->ident->toChars());
|
||||
}
|
||||
else if (!arg && varargs >= 0) {
|
||||
if (varargs == 0) {
|
||||
iarg->setName("_arguments");
|
||||
fdecl->llvmArguments = iarg;
|
||||
}
|
||||
else if (varargs == 1) {
|
||||
iarg->setName("_argptr");
|
||||
fdecl->llvmArgPtr = iarg;
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
varargs++;
|
||||
}
|
||||
else {
|
||||
iarg->setName("unnamed");
|
||||
}
|
||||
}
|
||||
|
||||
Logger::cout() << "func decl: " << *func << '\n';
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* DtoRealloc(llvm::Value* ptr, const llvm::Type* ty)
|
||||
{
|
||||
/*size_t sz = gTargetData->getTypeSize(ty);
|
||||
|
@ -1174,7 +776,7 @@ llvm::Value* DtoNestedVariable(VarDeclaration* vd)
|
|||
FuncDeclaration* fd = vd->toParent()->isFuncDeclaration();
|
||||
assert(fd != NULL);
|
||||
|
||||
IRFunction* fcur = &gIR->func();
|
||||
IRFunction* fcur = gIR->func();
|
||||
FuncDeclaration* f = fcur->decl;
|
||||
|
||||
// on this stack
|
||||
|
@ -1280,7 +882,7 @@ void DtoAssign(DValue* lhs, DValue* rhs)
|
|||
// assignment to this in constructor special case
|
||||
if (lhs->isThis()) {
|
||||
llvm::Value* tmp = rhs->getRVal();
|
||||
FuncDeclaration* fdecl = gIR->func().decl;
|
||||
FuncDeclaration* fdecl = gIR->func()->decl;
|
||||
// respecify the this param
|
||||
if (!llvm::isa<llvm::AllocaInst>(fdecl->llvmThisVar))
|
||||
fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint());
|
||||
|
@ -1716,3 +1318,113 @@ void DtoLazyStaticInit(bool istempl, llvm::Value* gvar, Initializer* init, Type*
|
|||
gIR->ir->CreateBr(endinitbb);
|
||||
gIR->scope() = IRScope(endinitbb,oldend);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoDefineDsymbol(Dsymbol* dsym)
|
||||
{
|
||||
if (StructDeclaration* sd = dsym->isStructDeclaration()) {
|
||||
DtoDefineStruct(sd);
|
||||
}
|
||||
else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
|
||||
DtoDefineClass(cd);
|
||||
}
|
||||
else if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
|
||||
DtoDefineFunc(fd);
|
||||
}
|
||||
else {
|
||||
error(dsym->loc, "unsupported dsymbol: %s", dsym->toChars());
|
||||
assert(0 && "unsupported dsymbol for DtoDefineDsymbol");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoConstInitDsymbol(Dsymbol* dsym)
|
||||
{
|
||||
if (StructDeclaration* sd = dsym->isStructDeclaration()) {
|
||||
DtoConstInitStruct(sd);
|
||||
}
|
||||
else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
|
||||
DtoConstInitClass(cd);
|
||||
}
|
||||
else if (VarDeclaration* vd = dsym->isVarDeclaration()) {
|
||||
DtoConstInitGlobal(vd);
|
||||
}
|
||||
else {
|
||||
error(dsym->loc, "unsupported dsymbol: %s", dsym->toChars());
|
||||
assert(0 && "unsupported dsymbol for DtoInitDsymbol");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoConstInitGlobal(VarDeclaration* vd)
|
||||
{
|
||||
Logger::println("DtoConstInitGlobal(%s)", vd->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
if (vd->llvmDModule) return;
|
||||
vd->llvmDModule = gIR->dmodule;
|
||||
|
||||
bool emitRTstaticInit = false;
|
||||
|
||||
llvm::Constant* _init = 0;
|
||||
if (vd->parent && vd->parent->isFuncDeclaration() && vd->init && vd->init->isExpInitializer()) {
|
||||
_init = DtoConstInitializer(vd->type, NULL);
|
||||
emitRTstaticInit = true;
|
||||
}
|
||||
else {
|
||||
_init = DtoConstInitializer(vd->type, vd->init);
|
||||
}
|
||||
|
||||
const llvm::Type* _type = DtoType(vd->type);
|
||||
Type* t = DtoDType(vd->type);
|
||||
|
||||
//Logger::cout() << "initializer: " << *_init << '\n';
|
||||
if (_type != _init->getType()) {
|
||||
Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n";
|
||||
// zero initalizer
|
||||
if (_init->isNullValue())
|
||||
_init = llvm::Constant::getNullValue(_type);
|
||||
// pointer to global constant (struct.init)
|
||||
else if (llvm::isa<llvm::GlobalVariable>(_init))
|
||||
{
|
||||
assert(_init->getType()->getContainedType(0) == _type);
|
||||
llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init);
|
||||
assert(t->ty == Tstruct);
|
||||
TypeStruct* ts = (TypeStruct*)t;
|
||||
assert(ts->sym->llvmInitZ);
|
||||
_init = ts->sym->llvmInitZ;
|
||||
}
|
||||
// array single value init
|
||||
else if (isaArray(_type))
|
||||
{
|
||||
_init = DtoConstStaticArray(_type, _init);
|
||||
}
|
||||
else {
|
||||
Logger::cout() << "Unexpected initializer type: " << *_type << '\n';
|
||||
//assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool istempl = false;
|
||||
if ((vd->storage_class & STCcomdat) || (vd->parent && DtoIsTemplateInstance(vd->parent))) {
|
||||
istempl = true;
|
||||
}
|
||||
|
||||
if (_init && _init->getType() != _type)
|
||||
_type = _init->getType();
|
||||
llvm::cast<llvm::OpaqueType>(vd->llvmIRGlobal->type.get())->refineAbstractTypeTo(_type);
|
||||
_type = vd->llvmIRGlobal->type.get();
|
||||
assert(!_type->isAbstract());
|
||||
|
||||
llvm::GlobalVariable* gvar = llvm::cast<llvm::GlobalVariable>(vd->llvmValue);
|
||||
if (!(vd->storage_class & STCextern) && (vd->getModule() == gIR->dmodule || istempl))
|
||||
{
|
||||
gvar->setInitializer(_init);
|
||||
}
|
||||
|
||||
if (emitRTstaticInit)
|
||||
DtoLazyStaticInit(istempl, gvar, vd->init, t);
|
||||
}
|
||||
|
|
14
gen/tollvm.h
14
gen/tollvm.h
|
@ -9,10 +9,6 @@ const llvm::Type* DtoType(Type* t);
|
|||
bool DtoIsPassedByRef(Type* type);
|
||||
Type* DtoDType(Type* t);
|
||||
|
||||
const llvm::FunctionType* DtoFunctionType(Type* t, const llvm::Type* thistype, bool ismain = false);
|
||||
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl);
|
||||
llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl);
|
||||
|
||||
const llvm::StructType* DtoDelegateType(Type* t);
|
||||
llvm::Value* DtoNullDelegate(llvm::Value* v);
|
||||
llvm::Value* DtoDelegateCopy(llvm::Value* dst, llvm::Value* src);
|
||||
|
@ -28,12 +24,8 @@ const llvm::Type* DtoSize_t();
|
|||
|
||||
const llvm::StructType* DtoComplexType(const llvm::Type* base);
|
||||
|
||||
void DtoMain();
|
||||
|
||||
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
|
||||
void DtoInitClass(TypeClass* tc, llvm::Value* dst);
|
||||
|
||||
llvm::Constant* DtoConstInitializer(Type* type, Initializer* init);
|
||||
llvm::Constant* DtoConstFieldInitializer(Type* type, Initializer* init);
|
||||
DValue* DtoInitializer(Initializer* init);
|
||||
|
||||
llvm::Function* LLVM_DeclareMemSet32();
|
||||
|
@ -66,7 +58,9 @@ bool DtoIsTemplateInstance(Dsymbol* s);
|
|||
|
||||
void DtoLazyStaticInit(bool istempl, llvm::Value* gvar, Initializer* init, Type* t);
|
||||
|
||||
void DtoClassInfo(ClassDeclaration* cd);
|
||||
void DtoDefineDsymbol(Dsymbol* dsym);
|
||||
void DtoConstInitDsymbol(Dsymbol* dsym);
|
||||
void DtoConstInitGlobal(VarDeclaration* vd);
|
||||
|
||||
// llvm wrappers
|
||||
void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
|
||||
|
|
739
gen/toobj.cpp
739
gen/toobj.cpp
|
@ -36,6 +36,8 @@
|
|||
#include "gen/tollvm.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/structs.h"
|
||||
#include "gen/classes.h"
|
||||
#include "gen/functions.h"
|
||||
#include "gen/todebug.h"
|
||||
#include "gen/runtime.h"
|
||||
|
||||
|
@ -90,12 +92,14 @@ Module::genobjfile()
|
|||
dsym->toObjFile();
|
||||
}
|
||||
|
||||
// check if there are queued function definitions, if so process their bodies now
|
||||
if (!ir.funcQueue.empty()) {
|
||||
size_t n = ir.funcQueue.size();
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
ir.funcQueue[i]->toObjFile();
|
||||
// process deferred const initializers
|
||||
for (size_t i=0; i<ir.constInitQueue.size(); ++i) {
|
||||
DtoConstInitDsymbol(ir.constInitQueue[i]);
|
||||
}
|
||||
|
||||
// process deferred definitions
|
||||
for (size_t i=0; i<ir.defineQueue.size(); ++i) {
|
||||
DtoDefineDsymbol(ir.defineQueue[i]);
|
||||
}
|
||||
|
||||
// generate ModuleInfo
|
||||
|
@ -322,183 +326,7 @@ void InterfaceDeclaration::toObjFile()
|
|||
|
||||
void StructDeclaration::toObjFile()
|
||||
{
|
||||
TypeStruct* ts = (TypeStruct*)DtoDType(type);
|
||||
if (llvmType != 0)
|
||||
return;
|
||||
|
||||
static int sdi = 0;
|
||||
Logger::print("StructDeclaration::toObjFile(%d): %s\n", sdi++, toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
gIR->structs.push_back(IRStruct(ts));
|
||||
|
||||
for (int k=0; k < members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(members->data[k]);
|
||||
dsym->toObjFile();
|
||||
}
|
||||
|
||||
Logger::println("doing struct fields");
|
||||
|
||||
const llvm::StructType* structtype = 0;
|
||||
std::vector<llvm::Constant*> fieldinits;
|
||||
|
||||
if (gIR->topstruct().offsets.empty())
|
||||
{
|
||||
std::vector<const llvm::Type*> fieldtypes;
|
||||
Logger::println("has no fields");
|
||||
fieldtypes.push_back(llvm::Type::Int8Ty);
|
||||
fieldinits.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
|
||||
structtype = llvm::StructType::get(fieldtypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::println("has fields");
|
||||
std::vector<const llvm::Type*> fieldtypes;
|
||||
unsigned prevsize = (unsigned)-1;
|
||||
unsigned lastoffset = (unsigned)-1;
|
||||
const llvm::Type* fieldtype = NULL;
|
||||
llvm::Constant* fieldinit = NULL;
|
||||
size_t fieldpad = 0;
|
||||
int idx = 0;
|
||||
for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) {
|
||||
// first iteration
|
||||
if (lastoffset == (unsigned)-1) {
|
||||
lastoffset = i->first;
|
||||
assert(lastoffset == 0);
|
||||
fieldtype = DtoType(i->second.var->type);
|
||||
fieldinit = i->second.init;
|
||||
prevsize = gTargetData->getTypeSize(fieldtype);
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
}
|
||||
// colliding offset?
|
||||
else if (lastoffset == i->first) {
|
||||
const llvm::Type* t = DtoType(i->second.var->type);
|
||||
size_t s = gTargetData->getTypeSize(t);
|
||||
if (s > prevsize) {
|
||||
fieldpad += s - prevsize;
|
||||
prevsize = s;
|
||||
}
|
||||
llvmHasUnions = true;
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
}
|
||||
// intersecting offset?
|
||||
else if (i->first < (lastoffset + prevsize)) {
|
||||
const llvm::Type* t = DtoType(i->second.var->type);
|
||||
size_t s = gTargetData->getTypeSize(t);
|
||||
assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size
|
||||
llvmHasUnions = true;
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s;
|
||||
}
|
||||
// fresh offset
|
||||
else {
|
||||
// commit the field
|
||||
fieldtypes.push_back(fieldtype);
|
||||
fieldinits.push_back(fieldinit);
|
||||
if (fieldpad) {
|
||||
// match up with below
|
||||
std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
|
||||
llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals);
|
||||
fieldtypes.push_back(c->getType());
|
||||
fieldinits.push_back(c);
|
||||
idx++;
|
||||
}
|
||||
|
||||
idx++;
|
||||
|
||||
// start new
|
||||
lastoffset = i->first;
|
||||
fieldtype = DtoType(i->second.var->type);
|
||||
fieldinit = i->second.init;
|
||||
prevsize = gTargetData->getTypeSize(fieldtype);
|
||||
i->second.var->llvmFieldIndex = idx;
|
||||
fieldpad = 0;
|
||||
}
|
||||
}
|
||||
fieldtypes.push_back(fieldtype);
|
||||
fieldinits.push_back(fieldinit);
|
||||
if (fieldpad) {
|
||||
// match up with above
|
||||
std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
|
||||
llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals);
|
||||
fieldtypes.push_back(c->getType());
|
||||
fieldinits.push_back(c);
|
||||
}
|
||||
|
||||
Logger::println("creating struct type");
|
||||
structtype = llvm::StructType::get(fieldtypes);
|
||||
}
|
||||
|
||||
// refine abstract types for stuff like: struct S{S* next;}
|
||||
if (gIR->topstruct().recty != 0)
|
||||
{
|
||||
llvm::PATypeHolder& pa = gIR->topstruct().recty;
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype);
|
||||
structtype = isaStruct(pa.get());
|
||||
}
|
||||
|
||||
ts->llvmType = structtype;
|
||||
llvmType = structtype;
|
||||
|
||||
if (parent->isModule()) {
|
||||
gIR->module->addTypeName(mangle(),ts->llvmType);
|
||||
}
|
||||
|
||||
llvmUnion = new DUnion; // uses gIR->topstruct()
|
||||
|
||||
// generate static data
|
||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
llvm::Constant* _init = 0;
|
||||
|
||||
// always generate the constant initalizer
|
||||
if (!zeroInit) {
|
||||
Logger::println("Not zero initialized");
|
||||
//assert(tk == gIR->gIR->topstruct()().size());
|
||||
#ifndef LLVMD_NO_LOGGER
|
||||
Logger::cout() << "struct type: " << *structtype << '\n';
|
||||
for (size_t k=0; k<fieldinits.size(); ++k) {
|
||||
Logger::cout() << "Type:" << '\n';
|
||||
Logger::cout() << *fieldinits[k]->getType() << '\n';
|
||||
Logger::cout() << "Value:" << '\n';
|
||||
Logger::cout() << *fieldinits[k] << '\n';
|
||||
}
|
||||
Logger::cout() << "Initializer printed" << '\n';
|
||||
#endif
|
||||
llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits);
|
||||
}
|
||||
else {
|
||||
Logger::println("Zero initialized");
|
||||
llvmInitZ = llvm::ConstantAggregateZero::get(structtype);
|
||||
}
|
||||
|
||||
// only provide the constant initializer for the defining module
|
||||
if (getModule() == gIR->dmodule)
|
||||
{
|
||||
_init = llvmInitZ;
|
||||
}
|
||||
|
||||
std::string initname("_D");
|
||||
initname.append(mangle());
|
||||
initname.append("6__initZ");
|
||||
llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module);
|
||||
ts->llvmInit = initvar;
|
||||
|
||||
// generate member function definitions
|
||||
gIR->topstruct().queueFuncs = false;
|
||||
IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
|
||||
size_t n = mfs.size();
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
//mfs[i]->toObjFile();
|
||||
gIR->funcQueue.push_back(mfs[i]);
|
||||
}
|
||||
|
||||
llvmDModule = gIR->dmodule;
|
||||
|
||||
gIR->structs.pop_back();
|
||||
|
||||
// generate typeinfo
|
||||
if (getModule() == gIR->dmodule && llvmInternal != LLVMnotypeinfo)
|
||||
type->getTypeInfo(NULL);
|
||||
DtoDeclareStruct(this);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
|
@ -534,186 +362,9 @@ void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>
|
|||
|
||||
/* ================================================================== */
|
||||
|
||||
static void LLVM_AddBaseClassData(BaseClasses* bcs)
|
||||
{
|
||||
// add base class data members first
|
||||
for (int j=0; j<bcs->dim; j++)
|
||||
{
|
||||
BaseClass* bc = (BaseClass*)(bcs->data[j]);
|
||||
assert(bc);
|
||||
Logger::println("Adding base class members of %s", bc->base->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
LLVM_AddBaseClassData(&bc->base->baseclasses);
|
||||
for (int k=0; k < bc->base->members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]);
|
||||
if (dsym->isVarDeclaration())
|
||||
{
|
||||
dsym->toObjFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassDeclaration::toObjFile()
|
||||
{
|
||||
TypeClass* ts = (TypeClass*)DtoDType(type);
|
||||
if (ts->llvmType != 0 || llvmInProgress)
|
||||
return;
|
||||
|
||||
llvmInProgress = true;
|
||||
|
||||
static int fdi = 0;
|
||||
Logger::print("ClassDeclaration::toObjFile(%d): %s\n", fdi++, toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
gIR->structs.push_back(IRStruct(ts));
|
||||
gIR->classes.push_back(this);
|
||||
|
||||
// add vtable
|
||||
llvm::PATypeHolder pa = llvm::OpaqueType::get();
|
||||
const llvm::Type* vtabty = llvm::PointerType::get(pa);
|
||||
|
||||
std::vector<const llvm::Type*> fieldtypes;
|
||||
fieldtypes.push_back(vtabty);
|
||||
|
||||
std::vector<llvm::Constant*> fieldinits;
|
||||
fieldinits.push_back(0);
|
||||
|
||||
// base classes first
|
||||
LLVM_AddBaseClassData(&baseclasses);
|
||||
|
||||
// then add own members
|
||||
for (int k=0; k < members->dim; k++) {
|
||||
Dsymbol* dsym = (Dsymbol*)(members->data[k]);
|
||||
dsym->toObjFile();
|
||||
}
|
||||
|
||||
// fill out fieldtypes/inits
|
||||
for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) {
|
||||
fieldtypes.push_back(DtoType(i->second.var->type));
|
||||
fieldinits.push_back(i->second.init);
|
||||
}
|
||||
|
||||
const llvm::StructType* structtype = llvm::StructType::get(fieldtypes);
|
||||
// refine abstract types for stuff like: class C {C next;}
|
||||
if (gIR->topstruct().recty != 0)
|
||||
{
|
||||
llvm::PATypeHolder& pa = gIR->topstruct().recty;
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype);
|
||||
structtype = isaStruct(pa.get());
|
||||
}
|
||||
|
||||
ts->llvmType = structtype;
|
||||
llvmType = structtype;
|
||||
|
||||
bool needs_definition = false;
|
||||
if (parent->isModule()) {
|
||||
gIR->module->addTypeName(mangle(),ts->llvmType);
|
||||
needs_definition = (getModule() == gIR->dmodule);
|
||||
}
|
||||
else {
|
||||
assert(0 && "class parent is not a module");
|
||||
}
|
||||
|
||||
// generate vtable
|
||||
llvm::GlobalVariable* svtblVar = 0;
|
||||
std::vector<llvm::Constant*> sinits;
|
||||
std::vector<const llvm::Type*> sinits_ty;
|
||||
sinits.reserve(vtbl.dim);
|
||||
sinits_ty.reserve(vtbl.dim);
|
||||
|
||||
for (int k=0; k < vtbl.dim; k++)
|
||||
{
|
||||
Dsymbol* dsym = (Dsymbol*)vtbl.data[k];
|
||||
assert(dsym);
|
||||
//Logger::cout() << "vtblsym: " << dsym->toChars() << '\n';
|
||||
|
||||
if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
|
||||
fd->toObjFile();
|
||||
assert(fd->llvmValue);
|
||||
llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
|
||||
sinits.push_back(c);
|
||||
sinits_ty.push_back(c->getType());
|
||||
}
|
||||
else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
|
||||
const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
llvm::Constant* c = llvm::Constant::getNullValue(cty);
|
||||
sinits.push_back(c);
|
||||
sinits_ty.push_back(cty);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
const llvm::StructType* svtbl_ty = 0;
|
||||
if (!sinits.empty())
|
||||
{
|
||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
|
||||
std::string varname("_D");
|
||||
varname.append(mangle());
|
||||
varname.append("6__vtblZ");
|
||||
|
||||
std::string styname(mangle());
|
||||
styname.append("__vtblTy");
|
||||
|
||||
svtbl_ty = llvm::StructType::get(sinits_ty);
|
||||
gIR->module->addTypeName(styname, svtbl_ty);
|
||||
svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module);
|
||||
|
||||
llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits));
|
||||
if (needs_definition)
|
||||
svtblVar->setInitializer(llvmConstVtbl);
|
||||
llvmVtbl = svtblVar;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// refine for final vtable type
|
||||
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty);
|
||||
svtbl_ty = isaStruct(pa.get());
|
||||
structtype = isaStruct(gIR->topstruct().recty.get());
|
||||
ts->llvmType = structtype;
|
||||
llvmType = structtype;
|
||||
|
||||
// generate initializer
|
||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
llvm::Constant* _init = 0;
|
||||
|
||||
// first field is always the vtable
|
||||
assert(svtblVar != 0);
|
||||
fieldinits[0] = svtblVar;
|
||||
|
||||
llvmInitZ = _init = llvm::ConstantStruct::get(structtype,fieldinits);
|
||||
assert(_init);
|
||||
|
||||
std::string initname("_D");
|
||||
initname.append(mangle());
|
||||
initname.append("6__initZ");
|
||||
//Logger::cout() << *_init << '\n';
|
||||
llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, NULL, initname, gIR->module);
|
||||
ts->llvmInit = initvar;
|
||||
|
||||
if (needs_definition) {
|
||||
initvar->setInitializer(_init);
|
||||
// generate member functions
|
||||
gIR->topstruct().queueFuncs = false;
|
||||
IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
|
||||
size_t n = mfs.size();
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
//mfs[i]->toObjFile();
|
||||
gIR->funcQueue.push_back(mfs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
gIR->classes.pop_back();
|
||||
gIR->structs.pop_back();
|
||||
|
||||
llvmInProgress = false;
|
||||
|
||||
// if (ClassDeclaration::classinfo != this)
|
||||
// DtoClassInfo(this);
|
||||
DtoDeclareClass(this);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
|
@ -732,7 +383,6 @@ void VarDeclaration::toObjFile()
|
|||
{
|
||||
Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
llvm::Module* M = gIR->module;
|
||||
|
||||
if (aliassym)
|
||||
{
|
||||
|
@ -747,81 +397,40 @@ void VarDeclaration::toObjFile()
|
|||
if (llvmTouched) return;
|
||||
else llvmTouched = true;
|
||||
|
||||
bool _isconst = false;
|
||||
if (isConst() && (init && !init->isExpInitializer()))
|
||||
_isconst = true;
|
||||
llvmIRGlobal = new IRGlobal(this);
|
||||
|
||||
Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());
|
||||
|
||||
bool _isconst = isConst();
|
||||
if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer())
|
||||
_isconst = false;
|
||||
|
||||
llvm::GlobalValue::LinkageTypes _linkage;
|
||||
bool istempl = false;
|
||||
bool static_local = false;
|
||||
if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) {
|
||||
_linkage = llvm::GlobalValue::WeakLinkage;
|
||||
istempl = true;
|
||||
}
|
||||
else if (parent && parent->isFuncDeclaration())
|
||||
else if (parent && parent->isFuncDeclaration()) {
|
||||
_linkage = llvm::GlobalValue::InternalLinkage;
|
||||
static_local = true;
|
||||
}
|
||||
else
|
||||
_linkage = DtoLinkage(protection, storage_class);
|
||||
|
||||
Type* t = DtoDType(type);
|
||||
|
||||
const llvm::Type* _type = DtoType(t);
|
||||
assert(_type);
|
||||
|
||||
llvm::Constant* _init = 0;
|
||||
bool _signed = !type->isunsigned();
|
||||
const llvm::Type* _type = llvmIRGlobal->type.get();
|
||||
|
||||
Logger::println("Creating global variable");
|
||||
std::string _name(mangle());
|
||||
|
||||
bool emitRTstaticInit = false;
|
||||
|
||||
if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl))
|
||||
{
|
||||
if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) {
|
||||
_init = DtoConstInitializer(t, NULL);
|
||||
emitRTstaticInit = true;
|
||||
}
|
||||
else {
|
||||
_init = DtoConstInitializer(t, init);
|
||||
}
|
||||
|
||||
//Logger::cout() << "initializer: " << *_init << '\n';
|
||||
if (_type != _init->getType()) {
|
||||
Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n";
|
||||
// zero initalizer
|
||||
if (_init->isNullValue())
|
||||
_init = llvm::Constant::getNullValue(_type);
|
||||
// pointer to global constant (struct.init)
|
||||
else if (llvm::isa<llvm::GlobalVariable>(_init))
|
||||
{
|
||||
assert(_init->getType()->getContainedType(0) == _type);
|
||||
llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init);
|
||||
assert(t->ty == Tstruct);
|
||||
TypeStruct* ts = (TypeStruct*)t;
|
||||
assert(ts->sym->llvmInitZ);
|
||||
_init = ts->sym->llvmInitZ;
|
||||
}
|
||||
// array single value init
|
||||
else if (isaArray(_type))
|
||||
{
|
||||
_init = DtoConstStaticArray(_type, _init);
|
||||
}
|
||||
else {
|
||||
Logger::cout() << "Unexpected initializer type: " << *_type << '\n';
|
||||
//assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_init && _init->getType() != _type)
|
||||
_type = _init->getType();
|
||||
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M);
|
||||
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,NULL,_name,gIR->module);
|
||||
llvmValue = gvar;
|
||||
|
||||
if (emitRTstaticInit)
|
||||
DtoLazyStaticInit(istempl, gvar, init, t);
|
||||
|
||||
llvmDModule = gIR->dmodule;
|
||||
if (static_local)
|
||||
DtoConstInitGlobal(this);
|
||||
else
|
||||
gIR->constInitQueue.push_back(this);
|
||||
|
||||
//if (storage_class & STCprivate)
|
||||
// gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility);
|
||||
|
@ -832,47 +441,10 @@ void VarDeclaration::toObjFile()
|
|||
{
|
||||
Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset);
|
||||
|
||||
Type* t = DtoDType(type);
|
||||
const llvm::Type* _type = DtoType(t);
|
||||
|
||||
llvm::Constant*_init = DtoConstInitializer(t, init);
|
||||
assert(_init);
|
||||
Logger::cout() << "field init is: " << *_init << " type should be " << *_type << '\n';
|
||||
if (_type != _init->getType())
|
||||
{
|
||||
if (t->ty == Tsarray)
|
||||
{
|
||||
const llvm::ArrayType* arrty = isaArray(_type);
|
||||
uint64_t n = arrty->getNumElements();
|
||||
std::vector<llvm::Constant*> vals(n,_init);
|
||||
_init = llvm::ConstantArray::get(arrty, vals);
|
||||
}
|
||||
else if (t->ty == Tarray)
|
||||
{
|
||||
assert(isaStruct(_type));
|
||||
_init = llvm::ConstantAggregateZero::get(_type);
|
||||
}
|
||||
else if (t->ty == Tstruct)
|
||||
{
|
||||
const llvm::StructType* structty = isaStruct(_type);
|
||||
TypeStruct* ts = (TypeStruct*)t;
|
||||
assert(ts);
|
||||
assert(ts->sym);
|
||||
assert(ts->sym->llvmInitZ);
|
||||
_init = ts->sym->llvmInitZ;
|
||||
}
|
||||
else if (t->ty == Tclass)
|
||||
{
|
||||
_init = llvm::Constant::getNullValue(_type);
|
||||
}
|
||||
else {
|
||||
Logger::println("failed for type %s", type->toChars());
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
const llvm::Type* _type = DtoType(type);
|
||||
|
||||
// add the field in the IRStruct
|
||||
gIR->topstruct().offsets.insert(std::make_pair(offset, IRStruct::Offset(this,_init)));
|
||||
gIR->topstruct()->offsets.insert(std::make_pair(offset, IRStruct::Offset(this, _type)));
|
||||
}
|
||||
|
||||
Logger::println("VarDeclaration::toObjFile is done");
|
||||
|
@ -901,254 +473,5 @@ void EnumDeclaration::toObjFile()
|
|||
|
||||
void FuncDeclaration::toObjFile()
|
||||
{
|
||||
if (llvmDModule) {
|
||||
assert(llvmValue != 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (llvmRunTimeHack) {
|
||||
Logger::println("runtime hack func chars: %s", toChars());
|
||||
if (!llvmValue)
|
||||
llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUnitTestDeclaration()) {
|
||||
Logger::attention("ignoring unittest declaration: %s", toChars());
|
||||
return;
|
||||
}
|
||||
|
||||
Type* t = DtoDType(type);
|
||||
TypeFunction* f = (TypeFunction*)t;
|
||||
|
||||
bool declareOnly = false;
|
||||
if (parent)
|
||||
{
|
||||
if (TemplateInstance* tinst = parent->isTemplateInstance()) {
|
||||
TemplateDeclaration* tempdecl = tinst->tempdecl;
|
||||
if (tempdecl->llvmInternal == LLVMva_start)
|
||||
{
|
||||
Logger::println("magic va_start found");
|
||||
llvmInternal = LLVMva_start;
|
||||
declareOnly = true;
|
||||
}
|
||||
else if (tempdecl->llvmInternal == LLVMva_arg)
|
||||
{
|
||||
Logger::println("magic va_arg found");
|
||||
llvmInternal = LLVMva_arg;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Function* func = DtoDeclareFunction(this);
|
||||
|
||||
if (declareOnly)
|
||||
return;
|
||||
|
||||
if (!gIR->structs.empty() && gIR->topstruct().queueFuncs) {
|
||||
if (!llvmQueued) {
|
||||
Logger::println("queueing %s", toChars());
|
||||
gIR->topstruct().funcs.push_back(this);
|
||||
llvmQueued = true;
|
||||
}
|
||||
return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete
|
||||
}
|
||||
|
||||
// debug info
|
||||
if (global.params.symdebug) {
|
||||
Module* mo = getModule();
|
||||
if (!mo->llvmCompileUnit) {
|
||||
mo->llvmCompileUnit = DtoDwarfCompileUnit(mo,false);
|
||||
}
|
||||
llvmDwarfSubProgram = DtoDwarfSubProgram(this, mo->llvmCompileUnit);
|
||||
}
|
||||
|
||||
assert(f->llvmType);
|
||||
const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0));
|
||||
|
||||
// template instances should have weak linkage
|
||||
if (parent && DtoIsTemplateInstance(parent)) {
|
||||
func->setLinkage(llvm::GlobalValue::WeakLinkage);
|
||||
}
|
||||
|
||||
// only members of the current module maybe be defined
|
||||
if (getModule() == gIR->dmodule || DtoIsTemplateInstance(parent))
|
||||
{
|
||||
llvmDModule = gIR->dmodule;
|
||||
|
||||
// handle static constructor / destructor
|
||||
if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) {
|
||||
const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1);
|
||||
//Logger::cout() << "static ctor type: " << *sctor_type << '\n';
|
||||
|
||||
llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue);
|
||||
//Logger::cout() << "static ctor func: " << *sctor_func << '\n';
|
||||
|
||||
llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1);
|
||||
|
||||
//Logger::cout() << "static ctor init: " << *sctor_init << '\n';
|
||||
|
||||
// output the llvm.global_ctors array
|
||||
const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array";
|
||||
llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module);
|
||||
}
|
||||
|
||||
// function definition
|
||||
if (fbody != 0)
|
||||
{
|
||||
gIR->functions.push_back(IRFunction(this));
|
||||
gIR->func().func = func;
|
||||
|
||||
// first make absolutely sure the type is up to date
|
||||
f->llvmType = llvmValue->getType()->getContainedType(0);
|
||||
|
||||
//Logger::cout() << "func type: " << *f->llvmType << '\n';
|
||||
|
||||
// this handling
|
||||
if (f->llvmUsesThis) {
|
||||
Logger::println("uses this");
|
||||
if (f->llvmRetInPtr)
|
||||
llvmThisVar = ++func->arg_begin();
|
||||
else
|
||||
llvmThisVar = func->arg_begin();
|
||||
assert(llvmThisVar != 0);
|
||||
}
|
||||
|
||||
if (isMain())
|
||||
gIR->emitMain = true;
|
||||
|
||||
llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func);
|
||||
llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func);
|
||||
|
||||
//assert(gIR->scopes.empty());
|
||||
gIR->scopes.push_back(IRScope(beginbb, endbb));
|
||||
|
||||
// create alloca point
|
||||
f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
|
||||
gIR->func().allocapoint = f->llvmAllocaPoint;
|
||||
|
||||
// give arguments storage
|
||||
size_t n = Argument::dim(f->parameters);
|
||||
for (int i=0; i < n; ++i) {
|
||||
Argument* arg = Argument::getNth(f->parameters, i);
|
||||
if (arg && arg->vardecl) {
|
||||
VarDeclaration* vd = arg->vardecl;
|
||||
if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))
|
||||
continue;
|
||||
llvm::Value* a = vd->llvmValue;
|
||||
assert(a);
|
||||
std::string s(a->getName());
|
||||
Logger::println("giving argument '%s' storage", s.c_str());
|
||||
s.append("_storage");
|
||||
llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint);
|
||||
gIR->ir->CreateStore(a,v);
|
||||
vd->llvmValue = v;
|
||||
}
|
||||
else {
|
||||
Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// debug info
|
||||
if (global.params.symdebug) DtoDwarfFuncStart(this);
|
||||
|
||||
llvm::Value* parentNested = NULL;
|
||||
if (FuncDeclaration* fd = toParent()->isFuncDeclaration()) {
|
||||
parentNested = fd->llvmNested;
|
||||
}
|
||||
|
||||
// construct nested variables struct
|
||||
if (!llvmNestedVars.empty() || parentNested) {
|
||||
std::vector<const llvm::Type*> nestTypes;
|
||||
int j = 0;
|
||||
if (parentNested) {
|
||||
nestTypes.push_back(parentNested->getType());
|
||||
j++;
|
||||
}
|
||||
for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) {
|
||||
VarDeclaration* vd = *i;
|
||||
vd->llvmNestedIndex = j++;
|
||||
if (vd->isParameter()) {
|
||||
assert(vd->llvmValue);
|
||||
nestTypes.push_back(vd->llvmValue->getType());
|
||||
}
|
||||
else {
|
||||
nestTypes.push_back(DtoType(vd->type));
|
||||
}
|
||||
}
|
||||
const llvm::StructType* nestSType = llvm::StructType::get(nestTypes);
|
||||
Logger::cout() << "nested var struct has type:" << '\n' << *nestSType;
|
||||
llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint);
|
||||
if (parentNested) {
|
||||
assert(llvmThisVar);
|
||||
llvm::Value* ptr = gIR->ir->CreateBitCast(llvmThisVar, parentNested->getType(), "tmp");
|
||||
gIR->ir->CreateStore(ptr, DtoGEPi(llvmNested, 0,0, "tmp"));
|
||||
}
|
||||
for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) {
|
||||
VarDeclaration* vd = *i;
|
||||
if (vd->isParameter()) {
|
||||
gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(llvmNested, 0, vd->llvmNestedIndex, "tmp"));
|
||||
vd->llvmValue = llvmNested;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy _argptr to a memory location
|
||||
if (f->linkage == LINKd && f->varargs == 1)
|
||||
{
|
||||
llvm::Value* argptrmem = new llvm::AllocaInst(llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint());
|
||||
new llvm::StoreInst(llvmArgPtr, argptrmem, gIR->scopebb());
|
||||
llvmArgPtr = argptrmem;
|
||||
}
|
||||
|
||||
// output function body
|
||||
fbody->toIR(gIR);
|
||||
|
||||
// llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
|
||||
// in automatically, so we do it here.
|
||||
if (!isMain()) {
|
||||
if (!gIR->scopereturned()) {
|
||||
// pass the previous block into this block
|
||||
if (global.params.symdebug) DtoDwarfFuncEnd(this);
|
||||
if (func->getReturnType() == llvm::Type::VoidTy) {
|
||||
new llvm::ReturnInst(gIR->scopebb());
|
||||
}
|
||||
else {
|
||||
new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// erase alloca point
|
||||
f->llvmAllocaPoint->eraseFromParent();
|
||||
f->llvmAllocaPoint = 0;
|
||||
gIR->func().allocapoint = 0;
|
||||
|
||||
gIR->scopes.pop_back();
|
||||
|
||||
// get rid of the endentry block, it's never used
|
||||
assert(!func->getBasicBlockList().empty());
|
||||
func->getBasicBlockList().pop_back();
|
||||
|
||||
// if the last block is empty now, it must be unreachable or it's a bug somewhere else
|
||||
// would be nice to figure out how to assert that this is correct
|
||||
llvm::BasicBlock* lastbb = &func->getBasicBlockList().back();
|
||||
if (lastbb->empty()) {
|
||||
if (lastbb->getNumUses() == 0)
|
||||
lastbb->eraseFromParent();
|
||||
else {
|
||||
new llvm::UnreachableInst(lastbb);
|
||||
/*if (func->getReturnType() == llvm::Type::VoidTy) {
|
||||
new llvm::ReturnInst(lastbb);
|
||||
}
|
||||
else {
|
||||
new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
gIR->functions.pop_back();
|
||||
}
|
||||
}
|
||||
DtoDeclareFunction(this);
|
||||
}
|
||||
|
|
163
gen/typinf.cpp
163
gen/typinf.cpp
|
@ -32,6 +32,7 @@
|
|||
#include "gen/runtime.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/structs.h"
|
||||
|
||||
/*******************************************
|
||||
* Get a canonicalized form of the TypeInfo for use with the internal
|
||||
|
@ -258,6 +259,7 @@ void TypeInfoDeclaration::toObjFile()
|
|||
}
|
||||
// custom typedef
|
||||
else {
|
||||
// emit globals
|
||||
toDt(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -279,12 +281,10 @@ void TypeInfoTypedefDeclaration::toDt(dt_t **pdt)
|
|||
ClassDeclaration* base = Type::typeinfotypedef;
|
||||
base->toObjFile();
|
||||
|
||||
llvm::Constant* initZ = base->llvmInitZ;
|
||||
assert(initZ);
|
||||
const llvm::StructType* stype = isaStruct(initZ->getType());
|
||||
const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
|
||||
|
||||
std::vector<llvm::Constant*> sinits;
|
||||
sinits.push_back(initZ->getOperand(0));
|
||||
sinits.push_back(base->llvmVtbl);
|
||||
|
||||
assert(tinfo->ty == Ttypedef);
|
||||
TypeTypedef *tc = (TypeTypedef *)tinfo;
|
||||
|
@ -301,13 +301,13 @@ void TypeInfoTypedefDeclaration::toDt(dt_t **pdt)
|
|||
sd->basetype->vtinfo->toObjFile();
|
||||
assert(llvm::isa<llvm::Constant>(sd->basetype->vtinfo->llvmValue));
|
||||
llvm::Constant* castbase = llvm::cast<llvm::Constant>(sd->basetype->vtinfo->llvmValue);
|
||||
castbase = llvm::ConstantExpr::getBitCast(castbase, initZ->getOperand(1)->getType());
|
||||
castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(1));
|
||||
sinits.push_back(castbase);
|
||||
|
||||
// char[] name
|
||||
char *name = sd->toPrettyChars();
|
||||
sinits.push_back(DtoConstString(name));
|
||||
assert(sinits.back()->getType() == initZ->getOperand(2)->getType());
|
||||
assert(sinits.back()->getType() == stype->getElementType(2));
|
||||
|
||||
// void[] init
|
||||
const llvm::PointerType* initpt = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
|
@ -343,12 +343,10 @@ void TypeInfoEnumDeclaration::toDt(dt_t **pdt)
|
|||
ClassDeclaration* base = Type::typeinfoenum;
|
||||
base->toObjFile();
|
||||
|
||||
llvm::Constant* initZ = base->llvmInitZ;
|
||||
assert(initZ);
|
||||
const llvm::StructType* stype = isaStruct(initZ->getType());
|
||||
const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
|
||||
|
||||
std::vector<llvm::Constant*> sinits;
|
||||
sinits.push_back(initZ->getOperand(0));
|
||||
sinits.push_back(base->llvmVtbl);
|
||||
|
||||
assert(tinfo->ty == Tenum);
|
||||
TypeEnum *tc = (TypeEnum *)tinfo;
|
||||
|
@ -365,13 +363,13 @@ void TypeInfoEnumDeclaration::toDt(dt_t **pdt)
|
|||
sd->memtype->vtinfo->toObjFile();
|
||||
assert(llvm::isa<llvm::Constant>(sd->memtype->vtinfo->llvmValue));
|
||||
llvm::Constant* castbase = llvm::cast<llvm::Constant>(sd->memtype->vtinfo->llvmValue);
|
||||
castbase = llvm::ConstantExpr::getBitCast(castbase, initZ->getOperand(1)->getType());
|
||||
castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(1));
|
||||
sinits.push_back(castbase);
|
||||
|
||||
// char[] name
|
||||
char *name = sd->toPrettyChars();
|
||||
sinits.push_back(DtoConstString(name));
|
||||
assert(sinits.back()->getType() == initZ->getOperand(2)->getType());
|
||||
assert(sinits.back()->getType() == stype->getElementType(2));
|
||||
|
||||
// void[] init
|
||||
const llvm::PointerType* initpt = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||
|
@ -405,12 +403,10 @@ static llvm::Constant* LLVM_D_Create_TypeInfoBase(Type* basetype, TypeInfoDeclar
|
|||
ClassDeclaration* base = cd;
|
||||
base->toObjFile();
|
||||
|
||||
llvm::Constant* initZ = base->llvmInitZ;
|
||||
assert(initZ);
|
||||
const llvm::StructType* stype = isaStruct(initZ->getType());
|
||||
const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
|
||||
|
||||
std::vector<llvm::Constant*> sinits;
|
||||
sinits.push_back(initZ->getOperand(0));
|
||||
sinits.push_back(base->llvmVtbl);
|
||||
|
||||
// TypeInfo base
|
||||
Logger::println("generating base typeinfo");
|
||||
|
@ -420,7 +416,7 @@ static llvm::Constant* LLVM_D_Create_TypeInfoBase(Type* basetype, TypeInfoDeclar
|
|||
basetype->vtinfo->toObjFile();
|
||||
assert(llvm::isa<llvm::Constant>(basetype->vtinfo->llvmValue));
|
||||
llvm::Constant* castbase = llvm::cast<llvm::Constant>(basetype->vtinfo->llvmValue);
|
||||
castbase = llvm::ConstantExpr::getBitCast(castbase, initZ->getOperand(1)->getType());
|
||||
castbase = llvm::ConstantExpr::getBitCast(castbase, stype->getElementType(1));
|
||||
sinits.push_back(castbase);
|
||||
|
||||
// create the symbol
|
||||
|
@ -538,11 +534,12 @@ void TypeInfoStructDeclaration::toDt(dt_t **pdt)
|
|||
TypeStruct *tc = (TypeStruct *)tinfo;
|
||||
StructDeclaration *sd = tc->sym;
|
||||
sd->toObjFile();
|
||||
DtoConstInitStruct(sd);
|
||||
|
||||
ClassDeclaration* base = Type::typeinfostruct;
|
||||
base->toObjFile();
|
||||
|
||||
const llvm::StructType* stype = isaStruct(base->llvmType);
|
||||
const llvm::StructType* stype = isaStruct(((TypeClass*)base->type)->llvmType->get());
|
||||
|
||||
std::vector<llvm::Constant*> sinits;
|
||||
sinits.push_back(base->llvmVtbl);
|
||||
|
@ -562,7 +559,7 @@ void TypeInfoStructDeclaration::toDt(dt_t **pdt)
|
|||
else
|
||||
{
|
||||
assert(sd->llvmInitZ);
|
||||
size_t cisize = gTargetData->getTypeSize(tc->llvmType);
|
||||
size_t cisize = gTargetData->getTypeSize(tc->llvmType->get());
|
||||
llvm::Constant* cicast = llvm::ConstantExpr::getBitCast(tc->llvmInit, initpt);
|
||||
sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast));
|
||||
}
|
||||
|
@ -778,131 +775,3 @@ void TypeInfoTupleDeclaration::toDt(dt_t **pdt)
|
|||
dtxoff(pdt, s, 0, TYnptr); // elements.ptr
|
||||
*/
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
/* ========================================================================= */
|
||||
/* CLASS INFO STUFF */
|
||||
/* ========================================================================= */
|
||||
/* ========================================================================= */
|
||||
|
||||
void DtoClassInfo(ClassDeclaration* cd)
|
||||
{
|
||||
// The layout is:
|
||||
// {
|
||||
// void **vptr;
|
||||
// monitor_t monitor;
|
||||
// byte[] initializer; // static initialization data
|
||||
// char[] name; // class name
|
||||
// void *[] vtbl;
|
||||
// Interface[] interfaces;
|
||||
// ClassInfo *base; // base class
|
||||
// void *destructor;
|
||||
// void *invariant; // class invariant
|
||||
// uint flags;
|
||||
// void *deallocator;
|
||||
// OffsetTypeInfo[] offTi;
|
||||
// void *defaultConstructor;
|
||||
// }
|
||||
|
||||
// holds the list of initializers for llvm
|
||||
std::vector<llvm::Constant*> inits;
|
||||
|
||||
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
|
||||
assert(cinfo);
|
||||
Logger::println("cinfo toObj");
|
||||
cinfo->toObjFile();
|
||||
|
||||
Logger::println("cinfo toObj done");
|
||||
assert(cinfo->type->ty == Tclass);
|
||||
TypeClass* tc = (TypeClass*)cinfo->type;
|
||||
//assert(tc->llvmInit);
|
||||
//assert(cinfo->llvmInitZ);
|
||||
|
||||
cinfo = ClassDeclaration::classinfo;
|
||||
assert(cinfo->llvmInitZ);
|
||||
|
||||
/*
|
||||
llvm::Constant* c;
|
||||
|
||||
// own vtable
|
||||
c = cinfo->llvmInitZ->getOperand(0);
|
||||
assert(c);
|
||||
inits.push_back(c);
|
||||
|
||||
// monitor
|
||||
// TODO no monitors yet
|
||||
|
||||
// initializer
|
||||
c = cinfo->llvmInitZ->getOperand(1);
|
||||
inits.push_back(c);
|
||||
|
||||
// class name
|
||||
// from dmd
|
||||
char *name = cd->ident->toChars();
|
||||
size_t namelen = strlen(name);
|
||||
if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
|
||||
{
|
||||
name = cd->toPrettyChars();
|
||||
namelen = strlen(name);
|
||||
}
|
||||
c = DtoConstString(name);
|
||||
inits.push_back(c);
|
||||
|
||||
// vtbl array
|
||||
c = cinfo->llvmInitZ->getOperand(3);
|
||||
inits.push_back(c);
|
||||
|
||||
// interfaces array
|
||||
c = cinfo->llvmInitZ->getOperand(4);
|
||||
inits.push_back(c);
|
||||
|
||||
// base classinfo
|
||||
c = cinfo->llvmInitZ->getOperand(5);
|
||||
inits.push_back(c);
|
||||
|
||||
// destructor
|
||||
c = cinfo->llvmInitZ->getOperand(5);
|
||||
inits.push_back(c);
|
||||
|
||||
// invariant
|
||||
c = cinfo->llvmInitZ->getOperand(6);
|
||||
inits.push_back(c);
|
||||
|
||||
// flags
|
||||
c = cinfo->llvmInitZ->getOperand(7);
|
||||
inits.push_back(c);
|
||||
|
||||
// allocator
|
||||
c = cinfo->llvmInitZ->getOperand(8);
|
||||
inits.push_back(c);
|
||||
|
||||
// offset typeinfo
|
||||
c = cinfo->llvmInitZ->getOperand(9);
|
||||
inits.push_back(c);
|
||||
|
||||
// default constructor
|
||||
c = cinfo->llvmInitZ->getOperand(10);
|
||||
inits.push_back(c);
|
||||
|
||||
// build the initializer
|
||||
const llvm::StructType* st = isaStruct(cinfo->llvmInitZ->getType());
|
||||
llvm::Constant* finalinit = llvm::ConstantStruct::get(st, inits);
|
||||
Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n';
|
||||
|
||||
assert(0);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -103,10 +103,14 @@ gen
|
|||
gen/arrays.cpp
|
||||
gen/arrays.h
|
||||
gen/binops.cpp
|
||||
gen/classes.cpp
|
||||
gen/classes.h
|
||||
gen/dvalue.cpp
|
||||
gen/dvalue.h
|
||||
gen/dwarftypes.cpp
|
||||
gen/enums.h
|
||||
gen/functions.cpp
|
||||
gen/functions.h
|
||||
gen/irstate.cpp
|
||||
gen/irstate.h
|
||||
gen/llvm.h
|
||||
|
@ -223,6 +227,7 @@ test/arrays.d
|
|||
test/arrays10.d
|
||||
test/arrays11.d
|
||||
test/arrays12.d
|
||||
test/arrays13.d
|
||||
test/arrays2.d
|
||||
test/arrays3.d
|
||||
test/arrays4.d
|
||||
|
@ -291,7 +296,9 @@ test/bug6.d
|
|||
test/bug60.d
|
||||
test/bug61.d
|
||||
test/bug62.d
|
||||
test/bug63.d
|
||||
test/bug64.d
|
||||
test/bug66.d
|
||||
test/bug7.d
|
||||
test/bug8.d
|
||||
test/bug9.d
|
||||
|
|
|
@ -88,40 +88,6 @@ void _d_array_init(void* a, size_t na, void* v, size_t nv)
|
|||
}
|
||||
}
|
||||
|
||||
// array comparison routines
|
||||
|
||||
bool _d_static_array_eq(void* lhs, void* rhs, size_t bytesize)
|
||||
{
|
||||
if (lhs is rhs)
|
||||
return true;
|
||||
return memcmp(lhs,rhs,bytesize) == 0;
|
||||
}
|
||||
|
||||
bool _d_static_array_neq(void* lhs, void* rhs, size_t bytesize)
|
||||
{
|
||||
if (lhs is rhs)
|
||||
return false;
|
||||
return memcmp(lhs,rhs,bytesize) != 0;
|
||||
}
|
||||
|
||||
bool _d_dyn_array_eq(void[] lhs, void[] rhs)
|
||||
{
|
||||
if (lhs.length != rhs.length)
|
||||
return false;
|
||||
else if (lhs is rhs)
|
||||
return true;
|
||||
return memcmp(lhs.ptr,rhs.ptr,lhs.length) == 0;
|
||||
}
|
||||
|
||||
bool _d_dyn_array_neq(void[] lhs, void[] rhs)
|
||||
{
|
||||
if (lhs.length != rhs.length)
|
||||
return true;
|
||||
else if (lhs is rhs)
|
||||
return false;
|
||||
return memcmp(lhs.ptr,rhs.ptr,lhs.length) != 0;
|
||||
}
|
||||
|
||||
// for array cast
|
||||
size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,11 @@ int main(string[] args) {
|
|||
|
||||
auto contents = listdir(".", "*.d");
|
||||
foreach(c; contents) {
|
||||
auto cmd = "llvmdc -quiet "~c;
|
||||
string cmd = "llvmdc -quiet "~c;
|
||||
foreach(v; args[1..$]) {
|
||||
cmd ~= ' ';
|
||||
cmd ~= v;
|
||||
}
|
||||
writefln(cmd);
|
||||
if (system(cmd) != 0) {
|
||||
bad ~= c;
|
||||
|
|
16
test/arrays13.d
Normal file
16
test/arrays13.d
Normal file
|
@ -0,0 +1,16 @@
|
|||
module arrays13;
|
||||
|
||||
void main()
|
||||
{
|
||||
string a = "hello";
|
||||
|
||||
assert(a > "hel");
|
||||
assert(a >= "hel");
|
||||
assert(a < "helloo");
|
||||
assert(a <= "helloo");
|
||||
assert(a > "betty");
|
||||
assert(a >= "betty");
|
||||
assert(a == "hello");
|
||||
assert(a <= "hello");
|
||||
assert(a >= "hello");
|
||||
}
|
10
test/bug63.d
Normal file
10
test/bug63.d
Normal file
|
@ -0,0 +1,10 @@
|
|||
module bug63;
|
||||
|
||||
void main()
|
||||
{
|
||||
static void notnested()
|
||||
{
|
||||
printf("hello world\n");
|
||||
}
|
||||
notnested();
|
||||
}
|
5
test/bug66.d
Normal file
5
test/bug66.d
Normal file
|
@ -0,0 +1,5 @@
|
|||
module bug66;
|
||||
import std.stdio;
|
||||
class Scene { string name() { return "Scene"; } }
|
||||
class Group : Scene { this () { } }
|
||||
void main() { writefln((new Group).name); }
|
|
@ -6,5 +6,5 @@ class C
|
|||
|
||||
void main()
|
||||
{
|
||||
auto ci = C.classinfo;
|
||||
ClassInfo ci = C.classinfo;
|
||||
}
|
||||
|
|
15
test/structs7.d
Normal file
15
test/structs7.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
module structs7;
|
||||
|
||||
pragma(LLVM_internal, "notypeinfo")
|
||||
struct S
|
||||
{
|
||||
int i;
|
||||
long l;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S s = void;
|
||||
int i = s.i;
|
||||
long l = s.l;
|
||||
}
|
|
@ -6,17 +6,18 @@ class C
|
|||
{
|
||||
}
|
||||
|
||||
void func()
|
||||
void func(bool b)
|
||||
{
|
||||
if (rand() & 1)
|
||||
if (b)
|
||||
throw new C;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool b = true;
|
||||
try
|
||||
{
|
||||
func();
|
||||
func(b);
|
||||
}
|
||||
catch(Object)
|
||||
{
|
||||
|
|
|
@ -4,11 +4,11 @@ typedef int int_t;
|
|||
|
||||
void main()
|
||||
{
|
||||
int_t i;
|
||||
/*int_t i;
|
||||
auto ti = typeid(typeof(i));
|
||||
printf("%s\n",ti.toString.ptr);
|
||||
assert(ti.toString() == "typeinfo3.int_t");
|
||||
assert(ti.next !is null);
|
||||
assert(ti.next.toString() == "int");
|
||||
assert(ti.init is null);
|
||||
assert(ti.init is null);*/
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue