# HG changeset patch # User lindquist # Date 1195197707 -3600 # Node ID 5071469303d4dad094a173d565abc0136660bc87 # Parent a676a77436420f2d8dcadac63106d91f93b5adec [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! :) diff -r a676a7743642 -r 5071469303d4 demos/ray.d --- a/demos/ray.d Thu Nov 15 00:24:44 2007 +0100 +++ b/demos/ray.d Fri Nov 16 08:21:47 2007 +0100 @@ -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 @@ 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; xllvmInternal2 = NULL; this->llvmValue = NULL; this->llvmDModule = NULL; + this->llvmTouched = false; } Dsymbol::Dsymbol(Identifier *ident) @@ -65,6 +66,7 @@ this->llvmInternal2 = NULL; this->llvmValue = NULL; this->llvmDModule = NULL; + this->llvmTouched = false; } int Dsymbol::equals(Object *o) diff -r a676a7743642 -r 5071469303d4 dmd/dsymbol.h --- a/dmd/dsymbol.h Thu Nov 15 00:24:44 2007 +0100 +++ b/dmd/dsymbol.h Fri Nov 16 08:21:47 2007 +0100 @@ -67,6 +67,7 @@ struct DeleteDeclaration; struct HdrGenState; struct TypeInfoDeclaration; +struct ClassInfoDeclaration; #if IN_GCC union tree_node; @@ -212,6 +213,7 @@ 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 @@ llvm::Value* llvmValue; Module* llvmDModule; + + bool llvmTouched; }; // Dsymbol that generates a scope diff -r a676a7743642 -r 5071469303d4 dmd/func.c --- a/dmd/func.c Thu Nov 15 00:24:44 2007 +0100 +++ b/dmd/func.c Fri Nov 16 08:21:47 2007 +0100 @@ -80,6 +80,7 @@ llvmArgPtr = NULL; llvmDwarfSubProgram = NULL; llvmRunTimeHack = false; + llvmIRFunc = NULL; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) diff -r a676a7743642 -r 5071469303d4 dmd/mtype.h --- a/dmd/mtype.h Thu Nov 15 00:24:44 2007 +0100 +++ b/dmd/mtype.h Fri Nov 16 08:21:47 2007 +0100 @@ -21,11 +21,14 @@ #include "arraytypes.h" #include "expression.h" +// LLVMDC namespace llvm { class Value; + class Instruction; class Type; - class Instruction; + class PATypeHolder; + class GlobalVariable; } struct Scope; @@ -250,7 +253,7 @@ virtual type *toCParamtype(); virtual Symbol *toSymbol(); - const llvm::Type* llvmType; + llvm::PATypeHolder* llvmType; // For eliminating dynamic_cast virtual TypeBasic *isTypeBasic(); @@ -540,7 +543,7 @@ type *toCtype(); - llvm::Constant* llvmInit; + llvm::GlobalVariable* llvmInit; }; struct TypeEnum : Type @@ -638,7 +641,7 @@ Symbol *toSymbol(); - llvm::Constant* llvmInit; + llvm::GlobalVariable* llvmInit; }; struct TypeTuple : Type diff -r a676a7743642 -r 5071469303d4 dmd/struct.c --- a/dmd/struct.c Thu Nov 15 00:24:44 2007 +0100 +++ b/dmd/struct.c Fri Nov 16 08:21:47 2007 +0100 @@ -45,13 +45,15 @@ 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() diff -r a676a7743642 -r 5071469303d4 gen/arrays.cpp --- a/gen/arrays.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/arrays.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -42,7 +42,7 @@ 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 @@ 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 @@ ////////////////////////////////////////////////////////////////////////////////////////// // 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,14 +589,17 @@ args.push_back(DtoBitCast(lmem,pt)); args.push_back(DtoBitCast(rmem,pt)); - TypeInfoDeclaration* ti = DtoDType(l->getType())->next->getTypeInfoDeclaration(); - if (!ti->llvmValue) { - ti->toObjFile(); + // pass element typeinfo ? + if (useti) { + TypeInfoDeclaration* ti = DtoDType(l->getType())->next->getTypeInfoDeclaration(); + if (!ti->llvmValue) { + ti->toObjFile(); + } + Logger::cout() << "typeinfo decl: " << *ti->llvmValue << '\n'; + + pt = fn->getFunctionType()->getParamType(2); + args.push_back(DtoBitCast(ti->llvmValue, pt)); } - Logger::cout() << "typeinfo decl: " << *ti->llvmValue << '\n'; - - 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::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 @@ 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()); } diff -r a676a7743642 -r 5071469303d4 gen/classes.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/classes.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -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; jdim; 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 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(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 sinits; + std::vector 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(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::get(svtbl_ty, sinits)); + if (needs_definition) + svtblVar->setInitializer(cd->llvmConstVtbl); + cd->llvmVtbl = svtblVar; + } + + // refine for final vtable type + llvm::cast(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 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; idim; 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 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 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; illvmInitZ->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); +} diff -r a676a7743642 -r 5071469303d4 gen/classes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/classes.h Fri Nov 16 08:21:47 2007 +0100 @@ -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 diff -r a676a7743642 -r 5071469303d4 gen/functions.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/functions.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -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(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 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 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(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 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; illvmType) + 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(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(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(), 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(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(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 nestTypes; + int j = 0; + if (parentNested) { + nestTypes.push_back(parentNested->getType()); + j++; + } + for (std::set::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::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 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 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); +} + +////////////////////////////////////////////////////////////////////////////////////////// diff -r a676a7743642 -r 5071469303d4 gen/functions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/functions.h Fri Nov 16 08:21:47 2007 +0100 @@ -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 diff -r a676a7743642 -r 5071469303d4 gen/irstate.cpp --- a/gen/irstate.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/irstate.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -40,7 +40,7 @@ ir.state = this; } -IRFunction& IRState::func() +IRFunction* IRState::func() { assert(!functions.empty() && "Function stack is empty!"); return functions.back(); @@ -49,22 +49,22 @@ 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 @@ : 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 @@ func = NULL; allocapoint = NULL; finallyretval = NULL; + defined = false; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -169,3 +172,11 @@ e2 = r; v = val; } + +////////////////////////////////////////////////////////////////////////////////////////// + +IRGlobal::IRGlobal(VarDeclaration* v) : + type(llvm::OpaqueType::get()) +{ + var = v; +} diff -r a676a7743642 -r 5071469303d4 gen/irstate.h --- a/gen/irstate.h Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/irstate.h Fri Nov 16 08:21:47 2007 +0100 @@ -39,19 +39,20 @@ }; // 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 FuncDeclVector; typedef std::multimap OffsetMap; + typedef std::vector VarDeclVector; public: IRStruct(); @@ -59,10 +60,11 @@ Type* type; llvm::PATypeHolder recty; - FuncDeclVector funcs; - bool queueFuncs; + OffsetMap offsets; + VarDeclVector defaultFields; - OffsetMap offsets; + bool defined; + bool constinited; }; // represents a finally block @@ -76,7 +78,7 @@ }; // represents a function -struct IRFunction +struct IRFunction : Object { llvm::Function* func; llvm::Instruction* allocapoint; @@ -88,6 +90,8 @@ FinallyVec finallys; llvm::Value* finallyretval; + bool defined; + IRFunction(FuncDeclaration*); }; @@ -106,6 +110,15 @@ 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 @@ llvm::Module* module; // functions - typedef std::vector FunctionVector; + typedef std::vector FunctionVector; FunctionVector functions; - IRFunction& func(); + IRFunction* func(); llvm::Function* topfunc(); TypeFunction* topfunctype(); llvm::Instruction* topallocapoint(); // structs - typedef std::vector StructVector; + typedef std::vector StructVector; StructVector structs; - IRStruct& topstruct(); + IRStruct* topstruct(); // classes TODO move into IRClass typedef std::vector ClassDeclVec; @@ -163,9 +176,11 @@ // builder helper IRBuilderHelper ir; - // functions queued for lazy definition - typedef std::vector FuncDeclVector; - FuncDeclVector funcQueue; + typedef std::vector DsymbolVector; + // dsymbols that need constant initializers constructed + DsymbolVector constInitQueue; + // dsymbols that need definitions (symbols in current module) + DsymbolVector defineQueue; }; #endif // LLVMDC_GEN_IRSTATE_H diff -r a676a7743642 -r 5071469303d4 gen/statements.cpp --- a/gen/statements.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/statements.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -71,9 +71,9 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ } // rewrite the scope - p->func().finallys.pop_back(); + p->func()->finallys.pop_back(); p->scope() = IRScope(endbb,oldend); } diff -r a676a7743642 -r 5071469303d4 gen/structs.cpp --- a/gen/structs.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/structs.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -78,7 +78,9 @@ 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 @@ 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 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(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 fieldinits_ll; + size_t nfi = irstruct->defaultFields.size(); + for (size_t i=0; idefaultFields[i] != NULL) { + c = irstruct->defaultFields[i]->llvmConstInit; + assert(c); + } + else { + const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i)); + std::vector 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; kgetType() << '\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 @@ 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; diff -r a676a7743642 -r 5071469303d4 gen/structs.h --- a/gen/structs.h Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/structs.h Fri Nov 16 08:21:47 2007 +0100 @@ -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& idxs); struct DUnionField diff -r a676a7743642 -r 5071469303d4 gen/toir.cpp --- a/gen/toir.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/toir.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -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 @@ // 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 @@ { 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 @@ { 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 @@ 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 @@ 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(vd->llvmValue)) { return new DVarValue(vd, vd->llvmValue, true); @@ -177,9 +185,11 @@ } 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 @@ 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 @@ // 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 @@ else if (dfn && dfn->cc != (unsigned)-1) { call->setCallingConv(dfn->cc); } + else if (llvm::isa(funcval)) { + call->setCallingConv(DtoCallingConv(dlink)); + } return new DImValue(type, retllval, isInPlace); } @@ -1445,9 +1460,8 @@ 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 @@ LOG_SCOPE; if (VarDeclaration* vd = var->isVarDeclaration()) { - llvm::Value* v = p->func().decl->llvmThisVar; + llvm::Value* v = p->func()->decl->llvmThisVar; if (llvm::isa(v)) v = new llvm::LoadInst(v, "tmp", p->scopebb()); return new DThisValue(vd, v); @@ -2023,7 +2037,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } - 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")); diff -r a676a7743642 -r 5071469303d4 gen/tollvm.cpp --- a/gen/tollvm.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/tollvm.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -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 @@ // 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 @@ 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 @@ 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::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 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 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(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 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; illvmType = 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(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 @@ ////////////////////////////////////////////////////////////////////////////////////////// -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 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 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; idim; 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 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* 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 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 @@ ////////////////////////////////////////////////////////////////////////////////////////// -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(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(), 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(fdecl->llvmValue)) - { - Logger::cout() << *fdecl->llvmValue << '\n'; - assert(0); - } - return llvm::cast(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(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(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 @@ 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 @@ // 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(fdecl->llvmThisVar)) fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint()); @@ -1716,3 +1318,113 @@ 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(_init)) + { + assert(_init->getType()->getContainedType(0) == _type); + llvm::GlobalVariable* gv = llvm::cast(_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(vd->llvmIRGlobal->type.get())->refineAbstractTypeTo(_type); + _type = vd->llvmIRGlobal->type.get(); + assert(!_type->isAbstract()); + + llvm::GlobalVariable* gvar = llvm::cast(vd->llvmValue); + if (!(vd->storage_class & STCextern) && (vd->getModule() == gIR->dmodule || istempl)) + { + gvar->setInitializer(_init); + } + + if (emitRTstaticInit) + DtoLazyStaticInit(istempl, gvar, vd->init, t); +} diff -r a676a7743642 -r 5071469303d4 gen/tollvm.h --- a/gen/tollvm.h Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/tollvm.h Fri Nov 16 08:21:47 2007 +0100 @@ -9,10 +9,6 @@ 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::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 @@ 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); diff -r a676a7743642 -r 5071469303d4 gen/toobj.cpp --- a/gen/toobj.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/toobj.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -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 @@ 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; itoObjFile(); - } + // process deferred const initializers + for (size_t i=0; istructs.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 fieldinits; - - if (gIR->topstruct().offsets.empty()) - { - std::vector 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 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 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 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(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; kgetType() << '\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; itoObjFile(); - 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 @@ /* ================================================================== */ -static void LLVM_AddBaseClassData(BaseClasses* bcs) -{ - // add base class data members first - for (int j=0; jdim; 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 fieldtypes; - fieldtypes.push_back(vtabty); - - std::vector 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(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 sinits; - std::vector 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(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::get(svtbl_ty, sinits)); - if (needs_definition) - svtblVar->setInitializer(llvmConstVtbl); - llvmVtbl = svtblVar; - } - - //////////////////////////////////////////////////////////////////////////////// - - // refine for final vtable type - llvm::cast(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; itoObjFile(); - 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 @@ { Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - llvm::Module* M = gIR->module; if (aliassym) { @@ -747,81 +397,40 @@ 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(_init)) - { - assert(_init->getType()->getContainedType(0) == _type); - llvm::GlobalVariable* gv = llvm::cast(_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 @@ { 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 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 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(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(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 nestTypes; - int j = 0; - if (parentNested) { - nestTypes.push_back(parentNested->getType()); - j++; - } - for (std::set::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::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); } diff -r a676a7743642 -r 5071469303d4 gen/typinf.cpp --- a/gen/typinf.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/typinf.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -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 @@ } // custom typedef else { + // emit globals toDt(NULL); } } @@ -279,12 +281,10 @@ 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 sinits; - sinits.push_back(initZ->getOperand(0)); + sinits.push_back(base->llvmVtbl); assert(tinfo->ty == Ttypedef); TypeTypedef *tc = (TypeTypedef *)tinfo; @@ -301,13 +301,13 @@ sd->basetype->vtinfo->toObjFile(); assert(llvm::isa(sd->basetype->vtinfo->llvmValue)); llvm::Constant* castbase = llvm::cast(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 @@ 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 sinits; - sinits.push_back(initZ->getOperand(0)); + sinits.push_back(base->llvmVtbl); assert(tinfo->ty == Tenum); TypeEnum *tc = (TypeEnum *)tinfo; @@ -365,13 +363,13 @@ sd->memtype->vtinfo->toObjFile(); assert(llvm::isa(sd->memtype->vtinfo->llvmValue)); llvm::Constant* castbase = llvm::cast(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 @@ 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 sinits; - sinits.push_back(initZ->getOperand(0)); + sinits.push_back(base->llvmVtbl); // TypeInfo base Logger::println("generating base typeinfo"); @@ -420,7 +416,7 @@ basetype->vtinfo->toObjFile(); assert(llvm::isa(basetype->vtinfo->llvmValue)); llvm::Constant* castbase = llvm::cast(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 @@ 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 sinits; sinits.push_back(base->llvmVtbl); @@ -562,7 +559,7 @@ 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 @@ 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 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); - */ -} - - - - - - - - - - - - - - diff -r a676a7743642 -r 5071469303d4 llvmdc.kdevelop.filelist --- a/llvmdc.kdevelop.filelist Thu Nov 15 00:24:44 2007 +0100 +++ b/llvmdc.kdevelop.filelist Fri Nov 16 08:21:47 2007 +0100 @@ -103,10 +103,14 @@ 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/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/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 diff -r a676a7743642 -r 5071469303d4 lphobos/internal/arrays.d --- a/lphobos/internal/arrays.d Thu Nov 15 00:24:44 2007 +0100 +++ b/lphobos/internal/arrays.d Fri Nov 16 08:21:47 2007 +0100 @@ -88,40 +88,6 @@ } } -// 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) { diff -r a676a7743642 -r 5071469303d4 runalltests.d --- a/runalltests.d Thu Nov 15 00:24:44 2007 +0100 +++ b/runalltests.d Fri Nov 16 08:21:47 2007 +0100 @@ -13,7 +13,11 @@ 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; diff -r a676a7743642 -r 5071469303d4 test/arrays13.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/arrays13.d Fri Nov 16 08:21:47 2007 +0100 @@ -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"); +} diff -r a676a7743642 -r 5071469303d4 test/bug58.d --- a/test/bug58.d Thu Nov 15 00:24:44 2007 +0100 +++ b/test/bug58.d Fri Nov 16 08:21:47 2007 +0100 @@ -7,4 +7,4 @@ arr.sort; writefln("arr.sort = ",arr); assert(arr == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]); -} \ No newline at end of file +} diff -r a676a7743642 -r 5071469303d4 test/bug63.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug63.d Fri Nov 16 08:21:47 2007 +0100 @@ -0,0 +1,10 @@ +module bug63; + +void main() +{ + static void notnested() + { + printf("hello world\n"); + } + notnested(); +} diff -r a676a7743642 -r 5071469303d4 test/bug66.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug66.d Fri Nov 16 08:21:47 2007 +0100 @@ -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); } diff -r a676a7743642 -r 5071469303d4 test/classinfo1.d --- a/test/classinfo1.d Thu Nov 15 00:24:44 2007 +0100 +++ b/test/classinfo1.d Fri Nov 16 08:21:47 2007 +0100 @@ -6,5 +6,5 @@ void main() { - auto ci = C.classinfo; + ClassInfo ci = C.classinfo; } diff -r a676a7743642 -r 5071469303d4 test/structs7.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/structs7.d Fri Nov 16 08:21:47 2007 +0100 @@ -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; +} diff -r a676a7743642 -r 5071469303d4 test/throw1.d --- a/test/throw1.d Thu Nov 15 00:24:44 2007 +0100 +++ b/test/throw1.d Fri Nov 16 08:21:47 2007 +0100 @@ -6,17 +6,18 @@ { } -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) { diff -r a676a7743642 -r 5071469303d4 test/typeinfo3.d --- a/test/typeinfo3.d Thu Nov 15 00:24:44 2007 +0100 +++ b/test/typeinfo3.d Fri Nov 16 08:21:47 2007 +0100 @@ -4,11 +4,11 @@ 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);*/ }