diff --git a/demos/qd.d b/demos/qd.d index c434aede..6a1ddfa9 100644 --- a/demos/qd.d +++ b/demos/qd.d @@ -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; diff --git a/demos/qd1.d b/demos/qd1.d new file mode 100644 index 00000000..2e11804f --- /dev/null +++ b/demos/qd1.d @@ -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); +} diff --git a/gen/toir.c b/gen/toir.c index b82a33a8..94169a21 100644 --- a/gen/toir.c +++ b/gen/toir.c @@ -64,7 +64,8 @@ elem* DeclarationExp::toElem(IRState* p) //allocainst->setAlignment(vd->type->alignsize()); // TODO vd->llvmValue = allocainst; } - DtoInitializer(vd->init); + elem* ie = DtoInitializer(vd->init); + delete ie; } } // struct declaration diff --git a/gen/tollvm.c b/gen/tollvm.c index 053d9cc9..f58b926d 100644 --- a/gen/tollvm.c +++ b/gen/tollvm.c @@ -890,17 +890,22 @@ llvm::Constant* DtoConstInitializer(Type* type, Initializer* init) ////////////////////////////////////////////////////////////////////////////////////////// -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 @@ llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, un ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb()); } + +////////////////////////////////////////////////////////////////////////////////////////// + +bool DtoIsTemplateInstance(Dsymbol* s) +{ + assert(s); + if (s->isTemplateInstance() && !s->isTemplateMixin()) + return true; + else if (s->parent) + return DtoIsTemplateInstance(s->parent); + return false; +} diff --git a/gen/tollvm.h b/gen/tollvm.h index b24468db..353818a1 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -34,7 +34,7 @@ void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance); 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 @@ void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes); llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs); +bool DtoIsTemplateInstance(Dsymbol* s); + #include "enums.h" diff --git a/gen/toobj.c b/gen/toobj.c index 913efa74..cf043a8b 100644 --- a/gen/toobj.c +++ b/gen/toobj.c @@ -569,16 +569,29 @@ void VarDeclaration::toObjFile() 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 @@ void VarDeclaration::toObjFile() 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 @@ void FuncDeclaration::toObjFile() assert(f->llvmType); const llvm::FunctionType* functype = llvm::cast(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 @@ void FuncDeclaration::toObjFile() 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 @@ void FuncDeclaration::toObjFile() gIR->functions.pop_back(); } - - // template instances should have weak linkage - if (parent->isTemplateInstance()) { - func->setLinkage(llvm::GlobalValue::WeakLinkage); - } } } diff --git a/test/templ1.d b/test/templ1.d new file mode 100644 index 00000000..de740fb3 --- /dev/null +++ b/test/templ1.d @@ -0,0 +1,11 @@ +module templ1; + +T func1(T)(T a) +{ + static T b = a; + return b; +} + +void main() +{ +} diff --git a/test/templ2.d b/test/templ2.d new file mode 100644 index 00000000..63d5ac7e --- /dev/null +++ b/test/templ2.d @@ -0,0 +1,7 @@ +module templ2; +import templ1; + +void main() +{ + func1(1); +}