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);
-        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/templ1.d	Fri Nov 02 06:32:32 2007 +0100
@@ -0,0 +1,11 @@
+module templ1;
+
+T func1(T)(T a)
+{
+    static T b = a;
+    return b;
+}
+
+void main()
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/templ2.d	Fri Nov 02 06:32:32 2007 +0100
@@ -0,0 +1,7 @@
+module templ2;
+import templ1;
+
+void main()
+{
+    func1(1);
+}