Mercurial > projects > ldc
changeset 50:6fcc08a4d406 trunk
[svn r54] Added support for nested delegates referencing parent's stack variables.
Replaced tester.sh with a version written in D.
A few bugfixes.
author | lindquist |
---|---|
date | Mon, 22 Oct 2007 15:40:56 +0200 |
parents | e5c4bece7fa1 |
children | 61bc1b4ad3c4 |
files | dmd/declaration.c dmd/declaration.h dmd/func.c gen/toir.c gen/tollvm.c gen/tollvm.h gen/toobj.c test/bug20.d test/bug21.d test/bug22.d test/bug23.d test/bug24.d test/bug25.d tester.d tester.sh |
diffstat | 15 files changed, 393 insertions(+), 70 deletions(-) [+] |
line wrap: on
line diff
--- a/dmd/declaration.c Fri Oct 19 17:43:46 2007 +0200 +++ b/dmd/declaration.c Mon Oct 22 15:40:56 2007 +0200 @@ -31,7 +31,7 @@ type = NULL; storage_class = STCundefined; protection = PROTundefined; - linkage = LINKdefault; + linkage = LINKdefault; llvmTouched = false; } @@ -549,6 +549,7 @@ onstack = 0; canassign = 0; value = NULL; + llvmNestedIndex = -1; } Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) @@ -1049,6 +1050,7 @@ 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()); } }
--- a/dmd/declaration.h Fri Oct 19 17:43:46 2007 +0200 +++ b/dmd/declaration.h Mon Oct 22 15:40:56 2007 +0200 @@ -15,6 +15,8 @@ #pragma once #endif /* __DMC__ */ +#include <set> + #include "dsymbol.h" #include "lexer.h" #include "mtype.h" @@ -125,8 +127,8 @@ Declaration *isDeclaration() { return this; } - virtual void toObjFile(); // compile to .obj file - + virtual void toObjFile(); // compile to .obj file + bool llvmTouched; }; @@ -255,6 +257,9 @@ // Eliminate need for dynamic_cast VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } + + // LLVMDC + int llvmNestedIndex; }; /**************************************************************/ @@ -514,6 +519,8 @@ bool llvmQueued; llvm::Value* llvmThisVar; + std::set<VarDeclaration*> llvmNestedVars; + llvm::Value* llvmNested; }; struct FuncAliasDeclaration : FuncDeclaration
--- a/dmd/func.c Fri Oct 19 17:43:46 2007 +0200 +++ b/dmd/func.c Mon Oct 22 15:40:56 2007 +0200 @@ -75,6 +75,7 @@ shidden = NULL; llvmQueued = false; llvmThisVar = NULL; + llvmNested = NULL; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
--- a/gen/toir.c Fri Oct 19 17:43:46 2007 +0200 +++ b/gen/toir.c Mon Oct 22 15:40:56 2007 +0200 @@ -41,20 +41,29 @@ { 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 @@ 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 @@ // 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 @@ // 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 @@ } } 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 @@ 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 @@ 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 @@ if (fd->llvmValue == 0) fd->toObjFile(); e->val = fd->llvmValue; - //e->aspointer = true; e->type = elem::FUNC; } assert(e != 0); @@ -2595,13 +2633,29 @@ 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 @@ new llvm::StoreInst(castfptr, fptr, p->scopebb()); e->inplace = true; + e->mem = lval; + e->type = elem::VAR; return e; }
--- a/gen/tollvm.c Fri Oct 19 17:43:46 2007 +0200 +++ b/gen/tollvm.c Mon Oct 22 15:40:56 2007 +0200 @@ -875,7 +875,7 @@ 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 @@ 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 @@ 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 @@ 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; +}
--- a/gen/tollvm.h Fri Oct 19 17:43:46 2007 +0200 +++ b/gen/tollvm.h Mon Oct 22 15:40:56 2007 +0200 @@ -40,10 +40,10 @@ 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 @@ llvm::Value* LLVM_DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expression* argexp); +llvm::Value* LLVM_DtoNestedVariable(VarDeclaration* vd); + #include "enums.h"
--- a/gen/toobj.c Fri Oct 19 17:43:46 2007 +0200 +++ b/gen/toobj.c Mon Oct 22 15:40:56 2007 +0200 @@ -699,6 +699,7 @@ // this handling if (f->llvmUsesThis) { + Logger::println("uses this"); if (f->llvmRetInPtr) llvmThisVar = ++func->arg_begin(); else @@ -719,6 +720,34 @@ 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 @@ if (func->getReturnType() == llvm::Type::VoidTy) { new llvm::ReturnInst(gIR->scopebb()); } - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug20.d Mon Oct 22 15:40:56 2007 +0200 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug21.d Mon Oct 22 15:40:56 2007 +0200 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug22.d Mon Oct 22 15:40:56 2007 +0200 @@ -0,0 +1,11 @@ +module bug22; + +void main() +{ + int i; + delegate { + i = 42; + }(); + printf("%d\n", i); + assert(i == 42); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug23.d Mon Oct 22 15:40:56 2007 +0200 @@ -0,0 +1,13 @@ +module bug23; +void main() +{ + int i; + delegate { + i++; + delegate { + i++; + }(); + }(); + printf("%d\n", i); + assert(i == 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug24.d Mon Oct 22 15:40:56 2007 +0200 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bug25.d Mon Oct 22 15:40:56 2007 +0200 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tester.d Mon Oct 22 15:40:56 2007 +0200 @@ -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; +}
--- a/tester.sh Fri Oct 19 17:43:46 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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