From 9a9999854f918d303c73f8e261e885cfaf529a10 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Tue, 13 Sep 2011 12:01:51 +0400 Subject: [PATCH] Named Return Value Optimization --- dmd2/statement.c | 12 ------------ gen/llvmhelpers.cpp | 43 +++++++++++++++++++++++++++++++++++++++++-- gen/statements.cpp | 15 ++++++++++----- gen/tocall.cpp | 2 +- ir/irfunction.cpp | 4 ++-- ir/irfuncty.h | 2 +- 6 files changed, 55 insertions(+), 23 deletions(-) diff --git a/dmd2/statement.c b/dmd2/statement.c index 3f735b06..ebd4fc41 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -3803,11 +3803,7 @@ Statement *ReturnStatement::semantic(Scope *sc) else { // Construct: return vresult; -#if IN_LLVM - if (!fd->vresult && !fd->isCtorDeclaration()) -#else if (!fd->vresult) -#endif { // Declare vresult VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); v->noscope = 1; @@ -3819,11 +3815,7 @@ Statement *ReturnStatement::semantic(Scope *sc) fd->vresult = v; } -#if IN_LLVM - s = new ReturnStatement(0, new VarExp(0, fd->isCtorDeclaration() ? fd->vthis : fd->vresult)); -#else s = new ReturnStatement(0, new VarExp(0, fd->vresult)); -#endif sc->fes->cases->push(s); // Construct: { vresult = exp; return cases->dim + 1; } @@ -3838,10 +3830,6 @@ Statement *ReturnStatement::semantic(Scope *sc) if (exp) { -#if IN_LLVM - if (!fd->isCtorDeclaration() && fd->returnLabel && tbret->ty != Tvoid) -#else -#endif if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration()) { // Function returns a reference if (tbret->isMutable()) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 80e6e4b0..8344e2b2 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1007,10 +1007,48 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) Logger::println("has nestedref set"); assert(vd->ir.irLocal); DtoNestedInit(vd); + // is it already allocated? + } else if(vd->ir.irLocal) { + // nothing to do... } - // normal stack variable, allocate storage on the stack if it has not already been done - else if(!vd->ir.irLocal && !vd->isRef()) { +#if DMDV2 + /* Named Return Value Optimization (NRVO): + T f(){ + T ret; // &ret == hidden pointer + ret = ... + return ret; // NRVO. + } + */ + else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) { vd->ir.irLocal = new IrLocal(vd); + vd->ir.irLocal->value = gIR->func()->retArg; + } +#endif + // normal stack variable, allocate storage on the stack if it has not already been done + else if(!vd->isRef()) { + vd->ir.irLocal = new IrLocal(vd); + +#if DMDV2 + /* NRVO again: + T t = f(); // t's memory address is taken hidden pointer + */ + ExpInitializer *ei = 0; + if (vd->type->toBasetype()->ty == Tstruct && vd->init && + !!(ei = vd->init->isExpInitializer())) + { + if (ei->exp->op == TOKconstruct) { + AssignExp *ae = (AssignExp*)ei->exp; + if (ae->e2->op == TOKcall) { + CallExp *ce = (CallExp *)ae->e2; + TypeFunction *tf = (TypeFunction *)ce->e1->type->toBasetype(); + if (tf->ty == Tfunction && tf->retStyle() == RETstack) { + vd->ir.irLocal->value = ce->toElem(gIR)->getLVal(); + goto Lexit; + } + } + } + } +#endif const LLType* lltype = DtoType(vd->type); @@ -1039,6 +1077,7 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? #if DMDV2 + Lexit: /* Mark the point of construction of a variable that needs to be destructed. */ if (vd->edtor && !vd->noscope) diff --git a/gen/statements.cpp b/gen/statements.cpp index d31361ec..4f74cf60 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -75,10 +75,9 @@ void ReturnStatement::toIR(IRState* p) DValue* e = exp->toElemDtor(p); // store return value DtoAssign(loc, rvar, e); - #if DMDV2 // call postblit if necessary - if (!p->func()->type->isref) + if (!p->func()->type->isref && !(f->decl->nrvo_can && f->decl->nrvo_var)) callPostblit(loc, exp, rvar->getLVal()); #endif @@ -101,14 +100,20 @@ void ReturnStatement::toIR(IRState* p) if (!exp && (p->topfunc() == p->mainFunc)) { v = LLConstant::getNullValue(p->mainFunc->getReturnType()); } else { - DValue* dval = exp->toElemDtor(p); #if DMDV2 + DValue* dval = 0; // call postblit if necessary - if (!p->func()->type->isref) + if (!p->func()->type->isref) { + dval = exp->toElemDtor(p); callPostblit(loc, exp, dval->getRVal()); + } else { + Expression *ae = exp->addressOf(NULL); + dval = ae->toElemDtor(p); + } // do abi specific transformations on the return value - v = p->func()->type->fty.putRet(exp->type, dval, p->func()->type->isref); + v = p->func()->type->fty.putRet(exp->type, dval); #else + DValue* dval = exp->toElemDtor(p); v = p->func()->type->fty.putRet(exp->type, dval); #endif } diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 29c71049..658cc031 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -373,7 +373,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // return in hidden ptr is first if (retinptr) { - LLValue* retvar = DtoRawAlloca(argiter->get()->getContainedType(0), 0, ".rettmp"); + LLValue* retvar = DtoRawAlloca(argiter->get()->getContainedType(0), resulttype->alignsize(), ".rettmp"); ++argiter; args.push_back(retvar); diff --git a/ir/irfunction.cpp b/ir/irfunction.cpp index f0d5937d..d9b4e5fd 100644 --- a/ir/irfunction.cpp +++ b/ir/irfunction.cpp @@ -30,7 +30,7 @@ bool IrFuncTyArg::isByVal() const { return (attrs & llvm::Attribute::ByVal) != 0 ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -llvm::Value* IrFuncTy::putRet(Type* dty, DValue* val, bool isref) +llvm::Value* IrFuncTy::putRet(Type* dty, DValue* val) { assert(!arg_sret); if (ret->rewrite) { @@ -38,7 +38,7 @@ llvm::Value* IrFuncTy::putRet(Type* dty, DValue* val, bool isref) LOG_SCOPE return ret->rewrite->put(dty, val); } - return isref ? val->getLVal() : val->getRVal(); + return val->getRVal(); } llvm::Value* IrFuncTy::getRet(Type* dty, DValue* val) diff --git a/ir/irfuncty.h b/ir/irfuncty.h index f04cca3c..c34eb0b9 100644 --- a/ir/irfuncty.h +++ b/ir/irfuncty.h @@ -102,7 +102,7 @@ struct IrFuncTy : IrBase reverseParams = false; } - llvm::Value* putRet(Type* dty, DValue* dval, bool isref = false); + llvm::Value* putRet(Type* dty, DValue* dval); llvm::Value* getRet(Type* dty, DValue* dval); llvm::Value* putParam(Type* dty, int idx, DValue* dval);