[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.)
This commit is contained in:
Tomas Lindquist Olsen
2007-11-02 06:32:32 +01:00
parent 3e3579da22
commit 1b867a0588
8 changed files with 114 additions and 36 deletions

View File

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

19
demos/qd1.d Normal file
View File

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

View File

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

View File

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

View File

@@ -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<unsigned>& idxs);
bool DtoIsTemplateInstance(Dsymbol* s);
#include "enums.h"

View File

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

11
test/templ1.d Normal file
View File

@@ -0,0 +1,11 @@
module templ1;
T func1(T)(T a)
{
static T b = a;
return b;
}
void main()
{
}

7
test/templ2.d Normal file
View File

@@ -0,0 +1,7 @@
module templ2;
import templ1;
void main()
{
func1(1);
}