mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-03-15 08:31:49 +01:00
[svn r54] Added support for nested delegates referencing parent's stack variables.
Replaced tester.sh with a version written in D. A few bugfixes.
This commit is contained in:
@@ -31,7 +31,7 @@ Declaration::Declaration(Identifier *id)
|
||||
type = NULL;
|
||||
storage_class = STCundefined;
|
||||
protection = PROTundefined;
|
||||
linkage = LINKdefault;
|
||||
linkage = LINKdefault;
|
||||
llvmTouched = false;
|
||||
}
|
||||
|
||||
@@ -549,6 +549,7 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer
|
||||
onstack = 0;
|
||||
canassign = 0;
|
||||
value = NULL;
|
||||
llvmNestedIndex = -1;
|
||||
}
|
||||
|
||||
Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
|
||||
@@ -1049,6 +1050,7 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
|
||||
fdthis->getLevel(loc, fdv);
|
||||
nestedref = 1;
|
||||
fdv->nestedFrameRef = 1;
|
||||
fdv->llvmNestedVars.insert(this);
|
||||
//printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "dsymbol.h"
|
||||
#include "lexer.h"
|
||||
#include "mtype.h"
|
||||
@@ -125,8 +127,8 @@ struct Declaration : Dsymbol
|
||||
|
||||
Declaration *isDeclaration() { return this; }
|
||||
|
||||
virtual void toObjFile(); // compile to .obj file
|
||||
|
||||
virtual void toObjFile(); // compile to .obj file
|
||||
|
||||
bool llvmTouched;
|
||||
};
|
||||
|
||||
@@ -255,6 +257,9 @@ struct VarDeclaration : Declaration
|
||||
|
||||
// Eliminate need for dynamic_cast
|
||||
VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
|
||||
|
||||
// LLVMDC
|
||||
int llvmNestedIndex;
|
||||
};
|
||||
|
||||
/**************************************************************/
|
||||
@@ -514,6 +519,8 @@ struct FuncDeclaration : Declaration
|
||||
|
||||
bool llvmQueued;
|
||||
llvm::Value* llvmThisVar;
|
||||
std::set<VarDeclaration*> llvmNestedVars;
|
||||
llvm::Value* llvmNested;
|
||||
};
|
||||
|
||||
struct FuncAliasDeclaration : FuncDeclaration
|
||||
|
||||
@@ -75,6 +75,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||
shidden = NULL;
|
||||
llvmQueued = false;
|
||||
llvmThisVar = NULL;
|
||||
llvmNested = NULL;
|
||||
}
|
||||
|
||||
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
||||
|
||||
102
gen/toir.c
102
gen/toir.c
@@ -41,20 +41,29 @@ elem* DeclarationExp::toElem(IRState* p)
|
||||
{
|
||||
Logger::println("VarDeclaration");
|
||||
|
||||
// static
|
||||
if (vd->isDataseg())
|
||||
{
|
||||
vd->toObjFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
// allocate storage on the stack
|
||||
Logger::println("vdtype = %s", vd->type->toChars());
|
||||
const llvm::Type* lltype = LLVM_DtoType(vd->type);
|
||||
llvm::AllocaInst* allocainst = new llvm::AllocaInst(lltype, vd->toChars(), p->topallocapoint());
|
||||
//allocainst->setAlignment(vd->type->alignsize()); // TODO
|
||||
vd->llvmValue = allocainst;
|
||||
// e->val = really needed??
|
||||
|
||||
// referenced by nested delegate?
|
||||
if (vd->nestedref) {
|
||||
Logger::println("has nestedref set");
|
||||
vd->llvmValue = p->func().decl->llvmNested;
|
||||
assert(vd->llvmValue);
|
||||
assert(vd->llvmNestedIndex >= 0);
|
||||
}
|
||||
// normal stack variable
|
||||
else {
|
||||
// allocate storage on the stack
|
||||
const llvm::Type* lltype = LLVM_DtoType(vd->type);
|
||||
llvm::AllocaInst* allocainst = new llvm::AllocaInst(lltype, vd->toChars(), p->topallocapoint());
|
||||
//allocainst->setAlignment(vd->type->alignsize()); // TODO
|
||||
vd->llvmValue = allocainst;
|
||||
}
|
||||
LLVM_DtoInitializer(vd->init);
|
||||
}
|
||||
}
|
||||
@@ -97,7 +106,11 @@ elem* VarExp::toElem(IRState* p)
|
||||
if (VarDeclaration* vd = var->isVarDeclaration())
|
||||
{
|
||||
Logger::println("VarDeclaration");
|
||||
|
||||
|
||||
if (vd->nestedref) {
|
||||
Logger::println("has nested ref");
|
||||
}
|
||||
|
||||
// needed to take care of forward references of global variables
|
||||
if (!vd->llvmTouched && vd->isDataseg())
|
||||
vd->toObjFile();
|
||||
@@ -111,6 +124,8 @@ elem* VarExp::toElem(IRState* p)
|
||||
// or it could be a forward declaration of a global variable
|
||||
if (!vd->llvmValue)
|
||||
{
|
||||
assert(!vd->nestedref);
|
||||
Logger::println("special - no llvmValue");
|
||||
// dollar
|
||||
if (!p->arrays.empty())
|
||||
{
|
||||
@@ -137,6 +152,7 @@ elem* VarExp::toElem(IRState* p)
|
||||
|
||||
// function parameter
|
||||
if (vd->storage_class & STCparameter) {
|
||||
assert(!vd->nestedref);
|
||||
Logger::println("function param");
|
||||
if (vd->storage_class & (STCref | STCout)) {
|
||||
e->mem = vd->llvmValue;
|
||||
@@ -163,8 +179,31 @@ elem* VarExp::toElem(IRState* p)
|
||||
}
|
||||
}
|
||||
else {
|
||||
e->mem = vd->llvmValue;
|
||||
//e->mem->setName(toChars());
|
||||
// nested variable
|
||||
if (vd->nestedref) {
|
||||
/*
|
||||
FuncDeclaration* fd = vd->toParent()->isFuncDeclaration();
|
||||
assert(fd != NULL);
|
||||
llvm::Value* ptr = NULL;
|
||||
// inside nested function
|
||||
if (fd != p->func().decl) {
|
||||
ptr = p->func().decl->llvmThisVar;
|
||||
Logger::cout() << "nested var reference:" << '\n' << *ptr << *vd->llvmValue->getType() << '\n';
|
||||
ptr = p->ir->CreateBitCast(ptr, vd->llvmValue->getType(), "tmp");
|
||||
}
|
||||
// inside the actual parent function
|
||||
else {
|
||||
ptr = vd->llvmValue;
|
||||
}
|
||||
assert(ptr);
|
||||
e->mem = LLVM_DtoGEPi(ptr,0,unsigned(vd->llvmNestedIndex),"tmp",p->scopebb());
|
||||
*/
|
||||
e->mem = LLVM_DtoNestedVariable(vd);
|
||||
}
|
||||
// normal local variable
|
||||
else {
|
||||
e->mem = vd->llvmValue;
|
||||
}
|
||||
e->vardecl = vd;
|
||||
e->type = elem::VAR;
|
||||
}
|
||||
@@ -1283,13 +1322,16 @@ elem* SymOffExp::toElem(IRState* p)
|
||||
Logger::println("VarDeclaration");
|
||||
assert(vd->llvmValue);
|
||||
Type* t = LLVM_DtoDType(type);
|
||||
Type* vdtype = LLVM_DtoDType(vd->type);
|
||||
Type* vdtype = LLVM_DtoDType(vd->type);
|
||||
|
||||
llvm::Value* llvalue = vd->nestedref ? LLVM_DtoNestedVariable(vd) : vd->llvmValue;
|
||||
|
||||
if (vdtype->ty == Tstruct && !(t->ty == Tpointer && t->next == vdtype)) {
|
||||
TypeStruct* vdt = (TypeStruct*)vdtype;
|
||||
e = new elem;
|
||||
std::vector<unsigned> dst(1,0);
|
||||
vdt->sym->offsetToIndex(t->next, offset, dst);
|
||||
llvm::Value* ptr = vd->llvmValue;
|
||||
llvm::Value* ptr = llvalue;
|
||||
assert(ptr);
|
||||
e->mem = LLVM_DtoGEP(ptr,dst,"tmp",p->scopebb());
|
||||
e->type = elem::VAL;
|
||||
@@ -1302,17 +1344,14 @@ elem* SymOffExp::toElem(IRState* p)
|
||||
e = new elem;
|
||||
llvm::Value* idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
||||
//llvm::Value* idx1 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
|
||||
e->mem = LLVM_DtoGEP(vd->llvmValue,idx0,idx0,"tmp",p->scopebb());
|
||||
e->arg = vd->llvmValue;
|
||||
e->mem = LLVM_DtoGEP(llvalue,idx0,idx0,"tmp",p->scopebb());
|
||||
e->arg = llvalue;
|
||||
e->type = elem::VAL;
|
||||
}
|
||||
else if (offset == 0) {
|
||||
/*if (!vd->llvmValue)
|
||||
vd->toObjFile();*/
|
||||
assert(vd->llvmValue);
|
||||
e = new elem;
|
||||
e->mem = vd->llvmValue;
|
||||
//e->vardecl = vd;
|
||||
assert(llvalue);
|
||||
e->mem = llvalue;
|
||||
e->type = elem::VAL;
|
||||
}
|
||||
else {
|
||||
@@ -1326,7 +1365,6 @@ elem* SymOffExp::toElem(IRState* p)
|
||||
if (fd->llvmValue == 0)
|
||||
fd->toObjFile();
|
||||
e->val = fd->llvmValue;
|
||||
//e->aspointer = true;
|
||||
e->type = elem::FUNC;
|
||||
}
|
||||
assert(e != 0);
|
||||
@@ -2595,13 +2633,29 @@ elem* FuncExp::toElem(IRState* p)
|
||||
|
||||
fd->toObjFile();
|
||||
|
||||
llvm::Value* lval = p->toplval();
|
||||
llvm::Value* lval = NULL;
|
||||
if (p->lvals.empty() || p->toplval() == NULL) {
|
||||
const llvm::Type* dgty = LLVM_DtoType(type);
|
||||
Logger::cout() << "delegate without explicit storage:" << '\n' << *dgty << '\n';
|
||||
lval = new llvm::AllocaInst(dgty,"dgstorage",p->topallocapoint());
|
||||
}
|
||||
else {
|
||||
lval = p->toplval();
|
||||
}
|
||||
|
||||
elem* e = new elem;
|
||||
|
||||
llvm::Value* context = LLVM_DtoGEPi(lval,0,0,"tmp",p->scopebb());
|
||||
//llvm::Value* castcontext = llvm::ConstantPointerNull::get(context->getType());
|
||||
//new llvm::StoreInst(castcontext, context, p->scopebb());
|
||||
const llvm::PointerType* pty = llvm::cast<llvm::PointerType>(context->getType()->getContainedType(0));
|
||||
llvm::Value* llvmNested = p->func().decl->llvmNested;
|
||||
if (llvmNested == NULL) {
|
||||
llvm::Value* nullcontext = llvm::ConstantPointerNull::get(pty);
|
||||
p->ir->CreateStore(nullcontext, context);
|
||||
}
|
||||
else {
|
||||
llvm::Value* nestedcontext = p->ir->CreateBitCast(llvmNested, pty, "tmp");
|
||||
p->ir->CreateStore(nestedcontext, context);
|
||||
}
|
||||
|
||||
llvm::Value* fptr = LLVM_DtoGEPi(lval,0,1,"tmp",p->scopebb());
|
||||
|
||||
@@ -2610,6 +2664,8 @@ elem* FuncExp::toElem(IRState* p)
|
||||
new llvm::StoreInst(castfptr, fptr, p->scopebb());
|
||||
|
||||
e->inplace = true;
|
||||
e->mem = lval;
|
||||
e->type = elem::VAR;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
50
gen/tollvm.c
50
gen/tollvm.c
@@ -875,7 +875,7 @@ llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, con
|
||||
v[0] = i0;
|
||||
v[1] = i1;
|
||||
Logger::cout() << "DtoGEP: " << *ptr << '\n';
|
||||
return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb);
|
||||
return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -892,14 +892,14 @@ llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, con
|
||||
dst[i] = llvm::ConstantInt::get(llvm::Type::Int32Ty, src[i], false);
|
||||
}
|
||||
ostr << '\n';
|
||||
return new llvm::GetElementPtrInst(ptr, dst.begin(), dst.end(), var, bb);
|
||||
return new llvm::GetElementPtrInst(ptr, dst.begin(), dst.end(), var, bb?bb:gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i, const std::string& var, llvm::BasicBlock* bb)
|
||||
{
|
||||
return new llvm::GetElementPtrInst(ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false), var, bb);
|
||||
return new llvm::GetElementPtrInst(ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false), var, bb?bb:gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -909,7 +909,7 @@ llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std:
|
||||
std::vector<llvm::Value*> v(2);
|
||||
v[0] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i0, false);
|
||||
v[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i1, false);
|
||||
return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb);
|
||||
return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1166,4 +1166,46 @@ llvm::Value* LLVM_DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expr
|
||||
return retval;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* LLVM_DtoNestedVariable(VarDeclaration* vd)
|
||||
{
|
||||
FuncDeclaration* fd = vd->toParent()->isFuncDeclaration();
|
||||
assert(fd != NULL);
|
||||
|
||||
IRFunction* fcur = &gIR->func();
|
||||
FuncDeclaration* f = fcur->decl;
|
||||
|
||||
// on this stack
|
||||
if (fd == f) {
|
||||
return LLVM_DtoGEPi(vd->llvmValue,0,unsigned(vd->llvmNestedIndex),"tmp");
|
||||
}
|
||||
|
||||
// on a caller stack
|
||||
llvm::Value* ptr = f->llvmThisVar;
|
||||
assert(ptr);
|
||||
|
||||
f = f->toParent()->isFuncDeclaration();
|
||||
assert(f);
|
||||
assert(f->llvmNested);
|
||||
const llvm::Type* nesttype = f->llvmNested->getType();
|
||||
assert(nesttype);
|
||||
|
||||
ptr = gIR->ir->CreateBitCast(ptr, nesttype, "tmp");
|
||||
|
||||
Logger::cout() << "nested var reference:" << '\n' << *ptr << *nesttype << '\n';
|
||||
|
||||
while (f) {
|
||||
if (fd == f) {
|
||||
return LLVM_DtoGEPi(ptr,0,vd->llvmNestedIndex,"tmp");
|
||||
}
|
||||
else {
|
||||
ptr = LLVM_DtoGEPi(ptr,0,0,"tmp");
|
||||
ptr = gIR->ir->CreateLoad(ptr,"tmp");
|
||||
}
|
||||
f = f->toParent()->isFuncDeclaration();
|
||||
}
|
||||
|
||||
assert(0 && "nested var not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
10
gen/tollvm.h
10
gen/tollvm.h
@@ -40,10 +40,10 @@ llvm::Function* LLVM_DeclareMemSet64();
|
||||
llvm::Function* LLVM_DeclareMemCpy32();
|
||||
llvm::Function* LLVM_DeclareMemCpy64();
|
||||
|
||||
llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const std::string& var, llvm::BasicBlock* bb);
|
||||
llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb);
|
||||
llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, const std::string& var, llvm::BasicBlock* bb);
|
||||
llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb);
|
||||
llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const std::string& var, llvm::BasicBlock* bb=NULL);
|
||||
llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb=NULL);
|
||||
llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, const std::string& var, llvm::BasicBlock* bb=NULL);
|
||||
llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb=NULL);
|
||||
|
||||
void LLVM_DtoGiveArgumentStorage(elem* e);
|
||||
|
||||
@@ -54,4 +54,6 @@ void LLVM_DtoAssert(llvm::Value* cond, llvm::Value* loc, llvm::Value* msg);
|
||||
|
||||
llvm::Value* LLVM_DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expression* argexp);
|
||||
|
||||
llvm::Value* LLVM_DtoNestedVariable(VarDeclaration* vd);
|
||||
|
||||
#include "enums.h"
|
||||
|
||||
30
gen/toobj.c
30
gen/toobj.c
@@ -699,6 +699,7 @@ void FuncDeclaration::toObjFile()
|
||||
|
||||
// this handling
|
||||
if (f->llvmUsesThis) {
|
||||
Logger::println("uses this");
|
||||
if (f->llvmRetInPtr)
|
||||
llvmThisVar = ++func->arg_begin();
|
||||
else
|
||||
@@ -719,6 +720,34 @@ void FuncDeclaration::toObjFile()
|
||||
f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
|
||||
gIR->func().allocapoint = f->llvmAllocaPoint;
|
||||
|
||||
llvm::Value* parentNested = NULL;
|
||||
if (FuncDeclaration* fd = toParent()->isFuncDeclaration()) {
|
||||
parentNested = fd->llvmNested;
|
||||
}
|
||||
|
||||
// construct nested variables struct
|
||||
if (!llvmNestedVars.empty() || parentNested) {
|
||||
std::vector<const llvm::Type*> nestTypes;
|
||||
int j = 0;
|
||||
if (parentNested) {
|
||||
nestTypes.push_back(parentNested->getType());
|
||||
j++;
|
||||
}
|
||||
for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) {
|
||||
VarDeclaration* vd = *i;
|
||||
vd->llvmNestedIndex = j++;
|
||||
nestTypes.push_back(LLVM_DtoType(vd->type));
|
||||
}
|
||||
const llvm::StructType* nestSType = llvm::StructType::get(nestTypes);
|
||||
Logger::cout() << "nested var struct has type:" << '\n' << *nestSType;
|
||||
llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint);
|
||||
if (parentNested) {
|
||||
assert(llvmThisVar);
|
||||
llvm::Value* ptr = gIR->ir->CreateBitCast(llvmThisVar, parentNested->getType(), "tmp");
|
||||
gIR->ir->CreateStore(ptr, LLVM_DtoGEPi(llvmNested, 0,0, "tmp"));
|
||||
}
|
||||
}
|
||||
|
||||
// output function body
|
||||
fbody->toIR(gIR);
|
||||
|
||||
@@ -731,7 +760,6 @@ void FuncDeclaration::toObjFile()
|
||||
if (func->getReturnType() == llvm::Type::VoidTy) {
|
||||
new llvm::ReturnInst(gIR->scopebb());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
test/bug20.d
Normal file
18
test/bug20.d
Normal file
@@ -0,0 +1,18 @@
|
||||
module bug20;
|
||||
|
||||
void func(void delegate() dg)
|
||||
{
|
||||
dg();
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int i = 42;
|
||||
void delegate() dg = {
|
||||
i++;
|
||||
};
|
||||
printf("i = %d\n",i);
|
||||
func(dg);
|
||||
printf("i = %d\n",i);
|
||||
assert(i == 43);
|
||||
}
|
||||
16
test/bug21.d
Normal file
16
test/bug21.d
Normal file
@@ -0,0 +1,16 @@
|
||||
module bug21;
|
||||
|
||||
void main()
|
||||
{
|
||||
int i = 42;
|
||||
auto a = {
|
||||
int j = i*2;
|
||||
auto b = {
|
||||
return j;
|
||||
};
|
||||
return b();
|
||||
};
|
||||
int i2 = a();
|
||||
printf("%d\n", i2);
|
||||
assert(i2 == i*2);
|
||||
}
|
||||
11
test/bug22.d
Normal file
11
test/bug22.d
Normal file
@@ -0,0 +1,11 @@
|
||||
module bug22;
|
||||
|
||||
void main()
|
||||
{
|
||||
int i;
|
||||
delegate {
|
||||
i = 42;
|
||||
}();
|
||||
printf("%d\n", i);
|
||||
assert(i == 42);
|
||||
}
|
||||
13
test/bug23.d
Normal file
13
test/bug23.d
Normal file
@@ -0,0 +1,13 @@
|
||||
module bug23;
|
||||
void main()
|
||||
{
|
||||
int i;
|
||||
delegate {
|
||||
i++;
|
||||
delegate {
|
||||
i++;
|
||||
}();
|
||||
}();
|
||||
printf("%d\n", i);
|
||||
assert(i == 2);
|
||||
}
|
||||
21
test/bug24.d
Normal file
21
test/bug24.d
Normal file
@@ -0,0 +1,21 @@
|
||||
module bug24;
|
||||
|
||||
struct S
|
||||
{
|
||||
long l;
|
||||
float f;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S s = S(3L,2f);
|
||||
delegate {
|
||||
S t = S(4L, 1f);
|
||||
delegate {
|
||||
s.l += t.l;
|
||||
s.f += t.f;
|
||||
}();
|
||||
}();
|
||||
printf("%lu %f\n", s.l, s.f);
|
||||
assert(s.l == 7 && s.f == 3);
|
||||
}
|
||||
12
test/bug25.d
Normal file
12
test/bug25.d
Normal file
@@ -0,0 +1,12 @@
|
||||
module bug25;
|
||||
|
||||
void main()
|
||||
{
|
||||
int i = 2;
|
||||
delegate {
|
||||
i = i*i;
|
||||
i += i*i;
|
||||
}();
|
||||
printf("%d\n", i);
|
||||
assert(i == 20);
|
||||
}
|
||||
129
tester.d
Normal file
129
tester.d
Normal file
@@ -0,0 +1,129 @@
|
||||
module tester;
|
||||
|
||||
import std.file;
|
||||
import std.path;
|
||||
import std.process;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
void printUsage(string cmd)
|
||||
{
|
||||
writefln("Usage:");
|
||||
writefln(" ",cmd," %%name %%cmd %%...");
|
||||
writefln("%%name:");
|
||||
writefln(" name of test without path or extension. eg: bug1");
|
||||
writefln("%%cmd:");
|
||||
writefln(" c = compile module");
|
||||
writefln(" gdb = same as 'c' but launches compiler in gdb");
|
||||
writefln(" ll = compile module and print the disassemled bitcode");
|
||||
writefln(" llo = compile and optimize module, then print the disassemled bitcode");
|
||||
writefln("%%...");
|
||||
writefln(" the rest of the command line options are passed directly to llvmdc");
|
||||
}
|
||||
|
||||
string testFileName(string test, string ext="")
|
||||
{
|
||||
return "test/"~test~ext;
|
||||
}
|
||||
|
||||
// couldnt get execvp to work
|
||||
int execute(string cmd)
|
||||
{
|
||||
return system(cmd);
|
||||
}
|
||||
int execute(string cmd, string[] args)
|
||||
{
|
||||
char[] c = cmd.dup;
|
||||
foreach(v; args) {
|
||||
c ~= ' ';
|
||||
c ~= v;
|
||||
}
|
||||
writefln(c);
|
||||
return system(c);
|
||||
}
|
||||
|
||||
void compileTest(string test, string[] args)
|
||||
{
|
||||
args = [testFileName(test,".d")] ~ args;
|
||||
if (execute("llvmdc", args) != 0) {
|
||||
throw new Exception("Failed to compile test: "~test);
|
||||
}
|
||||
}
|
||||
|
||||
void disassembleTest(string test, bool print)
|
||||
{
|
||||
string[] args = ["-f",testFileName(test,".bc")];
|
||||
if (execute("llvm-dis", args) != 0) {
|
||||
throw new Exception("Failed to disassemble test: "~test);
|
||||
}
|
||||
if (print) {
|
||||
execute("cat "~testFileName(test,".ll"));
|
||||
}
|
||||
}
|
||||
|
||||
void debugTest(string test, string[] common)
|
||||
{
|
||||
string[] args = ["--args", "llvmdc", testFileName(test,".d")];
|
||||
args ~= common;
|
||||
if (execute("gdb", args) != 0) {
|
||||
throw new Exception("Failed to compile test: '"~test~"' for debugging");
|
||||
}
|
||||
}
|
||||
|
||||
void optimizeTest(string test)
|
||||
{
|
||||
string bc = testFileName(test,".bc");
|
||||
if (execute("opt -std-compile-opts -f -o="~bc~" "~bc)) {
|
||||
throw new Exception("Failed to optimize test: "~test);
|
||||
}
|
||||
}
|
||||
|
||||
void runTest(string test)
|
||||
{
|
||||
if (execute(testFileName(test))) {
|
||||
throw new Exception("Failed to run test: "~test);
|
||||
}
|
||||
}
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
if (args.length < 3) {
|
||||
printUsage(args[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
string test = args[1];
|
||||
string kind = args[2];
|
||||
|
||||
string[] compilelink = ["-Itest","-odtest"];
|
||||
compilelink ~= args[3..$];
|
||||
string[] compileonly = compilelink.dup;
|
||||
|
||||
compileonly ~= "-c";
|
||||
compilelink ~= "-of"~testFileName(test);
|
||||
|
||||
switch(kind) {
|
||||
case "c":
|
||||
compileTest(test,compileonly);
|
||||
break;
|
||||
case "gdb":
|
||||
debugTest(test,compileonly);
|
||||
break;
|
||||
case "ll":
|
||||
compileTest(test,compileonly);
|
||||
disassembleTest(test,true);
|
||||
break;
|
||||
case "llo":
|
||||
compileTest(test,compileonly);
|
||||
optimizeTest(test);
|
||||
disassembleTest(test,true);
|
||||
break;
|
||||
case "run":
|
||||
compileTest(test,compilelink);
|
||||
runTest(test);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid command: "~kind);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
35
tester.sh
35
tester.sh
@@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z $1 ]; then
|
||||
echo "you need to specify the test name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$2" = "ll" ]; then
|
||||
llvmdc $1 -Itest -odtest -c -vv &&
|
||||
llvm-dis -f $1.bc &&
|
||||
cat $1.ll
|
||||
exit $?
|
||||
elif [ "$2" = "llopt" ]; then
|
||||
llvmdc $1 -Itest -odtest -c -vv &&
|
||||
opt -f -o=$1.bc -std-compile-opts $1.bc &&
|
||||
llvm-dis -f $1.bc &&
|
||||
cat $1.ll
|
||||
exit $?
|
||||
elif [ "$2" = "run" ]; then
|
||||
llvmdc $1 lib/lphobos.bc -Itest -odtest -of$1 -vv &&
|
||||
$1
|
||||
exit $?
|
||||
elif [ "$2" = "c" ]; then
|
||||
llvmdc $1 -Itest -odtest -c -vv
|
||||
exit $?
|
||||
elif [ "$2" = "gdb" ]; then
|
||||
gdb --args llvmdc $1 -Itest -odtest -c -vv
|
||||
exit $?
|
||||
elif [ "$2" = "gdbrun" ]; then
|
||||
llvmdc $1 -Itest -odtest -c -vv &&
|
||||
gdb $1
|
||||
exit $?
|
||||
else
|
||||
echo "bad command or filename"
|
||||
fi
|
||||
Reference in New Issue
Block a user