[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:
Tomas Lindquist Olsen 2007-11-16 08:21:47 +01:00
parent 7d6bbcd87d
commit d1cfe9524c
35 changed files with 1824 additions and 1452 deletions

View file

@ -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;

View file

@ -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; }
};

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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()

View file

@ -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
View 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
View 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
View 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
View 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

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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

View file

@ -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"));

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);
*/
}

View file

@ -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

View file

@ -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)
{

View file

@ -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
View 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
View file

@ -0,0 +1,10 @@
module bug63;
void main()
{
static void notnested()
{
printf("hello world\n");
}
notnested();
}

5
test/bug66.d Normal file
View 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); }

View file

@ -6,5 +6,5 @@ class C
void main()
{
auto ci = C.classinfo;
ClassInfo ci = C.classinfo;
}

15
test/structs7.d Normal file
View 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;
}

View file

@ -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)
{

View file

@ -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);*/
}