Mercurial > projects > ldc
changeset 85:f869c636a113 trunk
[svn r89] Fixed a bunch of problems with template instance across multiple modules.
Fixed initialization of function local static variables, with a non const initializer (now happens on first call using a global to make sure it only happens once.)
author | lindquist |
---|---|
date | Fri, 02 Nov 2007 06:32:32 +0100 |
parents | 169711a7126e |
children | fd32135dca3e |
files | demos/qd.d demos/qd1.d gen/toir.c gen/tollvm.c gen/tollvm.h gen/toobj.c test/templ1.d test/templ2.d |
diffstat | 8 files changed, 114 insertions(+), 36 deletions(-) [+] |
line wrap: on
line diff
--- a/demos/qd.d Fri Nov 02 02:27:41 2007 +0100 +++ b/demos/qd.d Fri Nov 02 06:32:32 2007 +0100 @@ -1,23 +1,5 @@ module qd; -import std.c.time: sleep; -void main() { - screen(640, 480); - pset(10, 10); - line(0, 0, 100, 100, Box, Back(Red~Black)); - for (int i=0; i<=100; i+=10) { - line(i, 0, 100-i, 100); - line(0, i, 100, 100-i); - } - circle(100, 100, 50, 15, White~Black, Fill=White~Black); - paint(200, 200, Red, Back=White); - circle(100, 100, 50, 15, White); - paint(200, 200, Black); - pset(10, 11); pset(10, 11, Black); - pset(10, 10); - sleep(5); -} - extern(C) { struct SDL_Rect { short x, y;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demos/qd1.d Fri Nov 02 06:32:32 2007 +0100 @@ -0,0 +1,19 @@ +module qd1; +import qd; +import std.c.time: sleep; +void main() { + screen(640, 480); + pset(10, 10); + line(0, 0, 100, 100, Box, Back(Red~Black)); + for (int i=0; i<=100; i+=10) { + line(i, 0, 100-i, 100); + line(0, i, 100, 100-i); + } + circle(100, 100, 50, 15, White~Black, Fill=White~Black); + paint(200, 200, Red, Back=White); + circle(100, 100, 50, 15, White); + paint(200, 200, Black); + pset(10, 11); pset(10, 11, Black); + pset(10, 10); + sleep(5); +}
--- a/gen/toir.c Fri Nov 02 02:27:41 2007 +0100 +++ b/gen/toir.c Fri Nov 02 06:32:32 2007 +0100 @@ -64,7 +64,8 @@ //allocainst->setAlignment(vd->type->alignsize()); // TODO vd->llvmValue = allocainst; } - DtoInitializer(vd->init); + elem* ie = DtoInitializer(vd->init); + delete ie; } } // struct declaration
--- a/gen/tollvm.c Fri Nov 02 02:27:41 2007 +0100 +++ b/gen/tollvm.c Fri Nov 02 06:32:32 2007 +0100 @@ -890,17 +890,22 @@ ////////////////////////////////////////////////////////////////////////////////////////// -void DtoInitializer(Initializer* init) +elem* DtoInitializer(Initializer* init) { if (ExpInitializer* ex = init->isExpInitializer()) { Logger::println("expression initializer"); - elem* e = ex->exp->toElem(gIR); - delete e; + return ex->exp->toElem(gIR); + } + else if (init->isVoidInitializer()) + { + // do nothing } else { Logger::println("unsupported initializer: %s", init->toChars()); + assert(0); } + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1460,3 +1465,15 @@ ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb()); } + +////////////////////////////////////////////////////////////////////////////////////////// + +bool DtoIsTemplateInstance(Dsymbol* s) +{ + assert(s); + if (s->isTemplateInstance() && !s->isTemplateMixin()) + return true; + else if (s->parent) + return DtoIsTemplateInstance(s->parent); + return false; +}
--- a/gen/tollvm.h Fri Nov 02 02:27:41 2007 +0100 +++ b/gen/tollvm.h Fri Nov 02 06:32:32 2007 +0100 @@ -34,7 +34,7 @@ void DtoInitClass(TypeClass* tc, llvm::Value* dst); llvm::Constant* DtoConstInitializer(Type* type, Initializer* init); -void DtoInitializer(Initializer* init); +elem* DtoInitializer(Initializer* init); llvm::Function* LLVM_DeclareMemSet32(); llvm::Function* LLVM_DeclareMemSet64(); @@ -68,4 +68,6 @@ llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs); +bool DtoIsTemplateInstance(Dsymbol* s); + #include "enums.h"
--- a/gen/toobj.c Fri Nov 02 02:27:41 2007 +0100 +++ b/gen/toobj.c Fri Nov 02 06:32:32 2007 +0100 @@ -569,16 +569,29 @@ LOG_SCOPE; llvm::Module* M = gIR->module; + if (aliassym) + { + toAlias()->toObjFile(); + return; + } + // global variable or magic - if (isDataseg() || parent->isModule()) + if (isDataseg()) { if (llvmTouched) return; else llvmTouched = true; - bool _isconst = isConst(); + bool _isconst = false; + if (isConst() && (init && !init->isExpInitializer())) + _isconst = true; llvm::GlobalValue::LinkageTypes _linkage; - if (parent && parent->isFuncDeclaration()) + bool istempl = false; + if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) { + _linkage = llvm::GlobalValue::WeakLinkage; + istempl = true; + } + else if (parent && parent->isFuncDeclaration()) _linkage = llvm::GlobalValue::InternalLinkage; else _linkage = DtoLinkage(protection, storage_class); @@ -597,10 +610,33 @@ llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,0,_name,M); llvmValue = gvar; - // if extern don't emit initializer - if (!(storage_class & STCextern) && getModule() == gIR->dmodule) + if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl)) { - _init = DtoConstInitializer(t, init); + if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) { + _init = DtoConstInitializer(t, NULL); + // create a flag to make sure initialization only happens once + llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage; + std::string gflagname(_name); + gflagname.append("__initflag"); + llvm::GlobalVariable* gflag = new llvm::GlobalVariable(llvm::Type::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,M); + + // check flag and do init if not already done + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* initbb = new llvm::BasicBlock("ifnotinit",gIR->topfunc(),oldend); + llvm::BasicBlock* endinitbb = new llvm::BasicBlock("ifnotinitend",gIR->topfunc(),oldend); + llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false)); + gIR->ir->CreateCondBr(cond, initbb, endinitbb); + gIR->scope() = IRScope(initbb,endinitbb); + elem* ie = DtoInitializer(init); + if (!ie->inplace) + DtoAssign(t, gvar, ie->getValue()); + gIR->ir->CreateStore(DtoConstBool(true), gflag); + gIR->ir->CreateBr(endinitbb); + gIR->scope() = IRScope(endinitbb,oldend); + } + else { + _init = DtoConstInitializer(t, init); + } //Logger::cout() << "initializer: " << *_init << '\n'; if (_type != _init->getType()) { @@ -765,8 +801,14 @@ assert(f->llvmType); const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0)); + // template instances should have weak linkage + assert(parent); + if (DtoIsTemplateInstance(parent)) { + func->setLinkage(llvm::GlobalValue::WeakLinkage); + } + // only members of the current module maybe be defined - if (getModule() == gIR->dmodule || parent->isTemplateInstance()) + if (getModule() == gIR->dmodule || DtoIsTemplateInstance(parent)) { llvmDModule = gIR->dmodule; @@ -838,7 +880,9 @@ gIR->ir->CreateStore(a,v); vd->llvmValue = v; } - else assert(0); + else { + Logger::println("*** ATTENTION: some unknown argument: %s", arg ? arg->toChars() : 0); + } } // debug info @@ -941,10 +985,5 @@ gIR->functions.pop_back(); } - - // template instances should have weak linkage - if (parent->isTemplateInstance()) { - func->setLinkage(llvm::GlobalValue::WeakLinkage); - } } }