mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-21 14:13:20 +01:00
[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:
18
demos/qd.d
18
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;
|
||||
|
||||
19
demos/qd1.d
Normal file
19
demos/qd1.d
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
23
gen/tollvm.c
23
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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
65
gen/toobj.c
65
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<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
11
test/templ1.d
Normal 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
7
test/templ2.d
Normal file
@@ -0,0 +1,7 @@
|
||||
module templ2;
|
||||
import templ1;
|
||||
|
||||
void main()
|
||||
{
|
||||
func1(1);
|
||||
}
|
||||
Reference in New Issue
Block a user