From 766fc30a301c464c6f0d1a92596147d7c88e56a6 Mon Sep 17 00:00:00 2001 From: Tomas Lindquist Olsen Date: Wed, 3 Oct 2007 04:56:32 +0200 Subject: [PATCH] [svn r19] * Added support for reassigning 'this' inside class constructors. * Added preliminary support for UnrolledLoopStatement. That is foreach on a tuple. --- dmd/declaration.h | 1 + dmd/func.c | 1 + gen/elem.c | 1 + gen/elem.h | 1 + gen/irstate.h | 5 ++++ gen/statements.c | 61 +++++++++++++++++++++++++++++++++++++++++++++-- gen/toir.c | 29 ++++++++++++++++------ gen/toobj.c | 13 ++++++++++ test/classes8.d | 22 +++++++++++++++++ test/unrolled.d | 13 ++++++++++ 10 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 test/classes8.d create mode 100644 test/unrolled.d diff --git a/dmd/declaration.h b/dmd/declaration.h index 49b2eb28..c6bf2585 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -511,6 +511,7 @@ struct FuncDeclaration : Declaration FuncDeclaration *isFuncDeclaration() { return this; } bool llvmQueued; + llvm::Value* llvmThisVar; }; struct FuncAliasDeclaration : FuncDeclaration diff --git a/dmd/func.c b/dmd/func.c index 7d3879e1..09a882fe 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -74,6 +74,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s nrvo_var = NULL; shidden = NULL; llvmQueued = false; + llvmThisVar = NULL; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) diff --git a/gen/elem.c b/gen/elem.c index fd691c25..cde3966f 100644 --- a/gen/elem.c +++ b/gen/elem.c @@ -18,6 +18,7 @@ elem::elem() inplace = false; field = false; callconv = (unsigned)-1; + isthis = false; vardecl = 0; funcdecl = 0; diff --git a/gen/elem.h b/gen/elem.h index deb824d9..86ba8674 100644 --- a/gen/elem.h +++ b/gen/elem.h @@ -32,6 +32,7 @@ public: bool inplace; bool field; unsigned callconv; + bool isthis; VarDeclaration* vardecl; FuncDeclaration* funcdecl; diff --git a/gen/irstate.h b/gen/irstate.h index cd9f050f..f9dfb060 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -78,9 +78,11 @@ struct IRState : Object // classes TODO move into IRClass typedef std::vector ClassDeclVec; ClassDeclVec classes; + typedef std::vector FuncDeclVec; typedef std::vector ClassMethodVec; ClassMethodVec classmethods; + typedef std::vector BoolVec; BoolVec queueClassMethods; @@ -111,6 +113,9 @@ struct IRState : Object // VarDeclaration for __dollar, but I can't see how to get the // array pointer from this :( LvalVec arrays; + + // keeping track of the declaration for the current function body + FuncDeclVec funcdecls; }; #endif // LLVMDC_GEN_IRSTATE_H diff --git a/gen/statements.c b/gen/statements.c index 00d455f2..81a50e6e 100644 --- a/gen/statements.c +++ b/gen/statements.c @@ -27,7 +27,7 @@ #include "gen/runtime.h" #include "gen/arrays.h" -/* --------------------------------------------------------------------------------------- */ +////////////////////////////////////////////////////////////////////////////// void CompoundStatement::toIR(IRState* p) { @@ -71,6 +71,8 @@ void CompoundStatement::toIR(IRState* p) //p->bbs.pop(); } +////////////////////////////////////////////////////////////////////////////// + void ReturnStatement::toIR(IRState* p) { static int rsi = 0; @@ -134,6 +136,8 @@ void ReturnStatement::toIR(IRState* p) p->scope().returned = true; } +////////////////////////////////////////////////////////////////////////////// + void ExpStatement::toIR(IRState* p) { static int esi = 0; @@ -150,6 +154,8 @@ void ExpStatement::toIR(IRState* p) p->buf.writenl();*/ } +////////////////////////////////////////////////////////////////////////////// + void IfStatement::toIR(IRState* p) { static int wsi = 0; @@ -204,6 +210,8 @@ void IfStatement::toIR(IRState* p) gIR->scope() = IRScope(endbb,oldend); } +////////////////////////////////////////////////////////////////////////////// + void ScopeStatement::toIR(IRState* p) { Logger::println("ScopeStatement::toIR(): %s", toChars()); @@ -240,6 +248,8 @@ void ScopeStatement::toIR(IRState* p) */ } +////////////////////////////////////////////////////////////////////////////// + void WhileStatement::toIR(IRState* p) { static int wsi = 0; @@ -281,6 +291,8 @@ void WhileStatement::toIR(IRState* p) gIR->scope() = IRScope(endbb,oldend); } +////////////////////////////////////////////////////////////////////////////// + void DoStatement::toIR(IRState* p) { static int wsi = 0; @@ -313,6 +325,8 @@ void DoStatement::toIR(IRState* p) gIR->scope() = IRScope(endbb,oldend); } +////////////////////////////////////////////////////////////////////////////// + void ForStatement::toIR(IRState* p) { static int wsi = 0; @@ -374,6 +388,8 @@ void ForStatement::toIR(IRState* p) gIR->scope() = IRScope(endbb,oldend); } +////////////////////////////////////////////////////////////////////////////// + void BreakStatement::toIR(IRState* p) { static int wsi = 0; @@ -389,6 +405,8 @@ void BreakStatement::toIR(IRState* p) } } +////////////////////////////////////////////////////////////////////////////// + void ContinueStatement::toIR(IRState* p) { static int wsi = 0; @@ -404,6 +422,8 @@ void ContinueStatement::toIR(IRState* p) } } +////////////////////////////////////////////////////////////////////////////// + void OnScopeStatement::toIR(IRState* p) { static int wsi = 0; @@ -414,6 +434,8 @@ void OnScopeStatement::toIR(IRState* p) //statement->toIR(p); // this seems to be redundant } +////////////////////////////////////////////////////////////////////////////// + void TryFinallyStatement::toIR(IRState* p) { static int wsi = 0; @@ -446,6 +468,8 @@ void TryFinallyStatement::toIR(IRState* p) gIR->scope() = IRScope(endbb,oldend); } +////////////////////////////////////////////////////////////////////////////// + void TryCatchStatement::toIR(IRState* p) { static int wsi = 0; @@ -465,6 +489,8 @@ void TryCatchStatement::toIR(IRState* p) } } +////////////////////////////////////////////////////////////////////////////// + void ThrowStatement::toIR(IRState* p) { static int wsi = 0; @@ -478,6 +504,8 @@ void ThrowStatement::toIR(IRState* p) delete e; } +////////////////////////////////////////////////////////////////////////////// + void SwitchStatement::toIR(IRState* p) { Logger::println("SwitchStatement::toIR(): %s", toChars()); @@ -561,6 +589,35 @@ void SwitchStatement::toIR(IRState* p) gIR->scope() = IRScope(endbb,oldend); } +////////////////////////////////////////////////////////////////////////////// + +void UnrolledLoopStatement::toIR(IRState* p) +{ + Logger::println("UnrolledLoopStatement::toIR(): %s", toChars()); + LOG_SCOPE; + + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* endbb = new llvm::BasicBlock("unrolledend", p->topfunc(), oldend); + + p->scope() = IRScope(p->scopebb(),endbb); + p->loopbbs.push_back(IRScope(p->scopebb(),endbb)); + + for (int i=0; idim; ++i) + { + Statement* s = (Statement*)statements->data[i]; + s->toIR(p); + } + + p->loopbbs.pop_back(); + + new llvm::BranchInst(endbb, p->scopebb()); + p->scope() = IRScope(endbb,oldend); +} + +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// + #define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();} //STUBST(BreakStatement); //STUBST(ForStatement); @@ -589,5 +646,5 @@ STUBST(LabelStatement); STUBST(GotoCaseStatement); STUBST(GotoDefaultStatement); STUBST(GotoStatement); -STUBST(UnrolledLoopStatement); +//STUBST(UnrolledLoopStatement); //STUBST(OnScopeStatement); diff --git a/gen/toir.c b/gen/toir.c index 5f0defe5..88d617bf 100644 --- a/gen/toir.c +++ b/gen/toir.c @@ -384,8 +384,19 @@ elem* AssignExp::toElem(IRState* p) else if (e1ty == Tclass) { if (e2ty == Tclass) { llvm::Value* tmp = r->getValue(); - Logger::cout() << "tmp: " << *tmp << ", " << *l->mem << '\n'; - new llvm::StoreInst(tmp, l->mem, p->scopebb()); + Logger::cout() << "tmp: " << *tmp << " ||| " << *l->mem << '\n'; + // assignment to this in constructor special case + if (l->isthis) { + FuncDeclaration* fdecl = p->funcdecls.back(); + // respecify the this param + if (!llvm::isa(fdecl->llvmThisVar)) + fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", p->topallocapoint()); + new llvm::StoreInst(tmp, fdecl->llvmThisVar, p->scopebb()); + } + // regular class ref -> class ref assignment + else { + new llvm::StoreInst(tmp, l->mem, p->scopebb()); + } } else assert(0); @@ -1218,7 +1229,7 @@ elem* DotVarExp::toElem(IRState* p) TypeStruct* ts = (TypeStruct*)e1->type->next; ts->sym->offsetToIndex(vd->offset, vdoffsets); Logger::println("Struct member offset:%d", vd->offset); - src = l->val; + src = l->val ? l->val : l->mem; } else if (e1->type->ty == Tclass) { TypeClass* tc = (TypeClass*)e1->type; @@ -1279,7 +1290,7 @@ elem* ThisExp::toElem(IRState* p) elem* e = new elem; if (VarDeclaration* vd = var->isVarDeclaration()) { - assert(vd->llvmValue == 0); + /*assert(vd->llvmValue == 0); llvm::Function* fn = p->topfunc(); assert(fn); @@ -1292,10 +1303,14 @@ elem* ThisExp::toElem(IRState* p) v = ++fn->arg_begin(); else v = fn->arg_begin(); - assert(v); + assert(v);*/ - e->val = v; + llvm::Value* v = p->funcdecls.back()->llvmThisVar; + if (llvm::isa(v)) + v = new llvm::LoadInst(v, "tmp", p->scopebb()); + e->mem = v; e->type = elem::VAL; + e->isthis = true; } else { assert(0); @@ -1794,7 +1809,7 @@ elem* NewExp::toElem(IRState* p) e->inplace = true; e->type = elem::VAR; - + return e; } diff --git a/gen/toobj.c b/gen/toobj.c index f5c73139..061b5361 100644 --- a/gen/toobj.c +++ b/gen/toobj.c @@ -665,9 +665,20 @@ void FuncDeclaration::toObjFile() // function definition if (allow_fbody && fbody != 0) { + gIR->funcdecls.push_back(this); + // first make absolutely sure the type is up to date f->llvmType = llvmValue->getType()->getContainedType(0); + // this handling + if (f->llvmUsesThis) { + if (f->llvmRetInPtr) + llvmThisVar = ++func->arg_begin(); + else + llvmThisVar = func->arg_begin(); + assert(llvmThisVar != 0); + } + if (isMain()) gIR->emitMain = true; @@ -716,6 +727,8 @@ void FuncDeclaration::toObjFile() // possibly assert(lastbb->getNumPredecessors() == 0); ??? try it out sometime ... new llvm::UnreachableInst(lastbb); } + + gIR->funcdecls.pop_back(); } } } diff --git a/test/classes8.d b/test/classes8.d new file mode 100644 index 00000000..b96bc7cf --- /dev/null +++ b/test/classes8.d @@ -0,0 +1,22 @@ +class A { + int i; + int l; + this(bool b,bool b2=false) { + if (b) this = new B; + i = 4; + if (b2) this = new C; + l = 64; + } +} +class B : A{ + this() { + super(false); + } +} +class C : A{ + this() { + super(false); + } +} +void main() { +} diff --git a/test/unrolled.d b/test/unrolled.d new file mode 100644 index 00000000..17e0df56 --- /dev/null +++ b/test/unrolled.d @@ -0,0 +1,13 @@ +module unrolled; + +void test(T...)(T t) { + foreach (value; t) { + printf("%d\n", value); + if (value == 2) + break; + } +} + +void main() { + test(1,4,3); +}