Named Return Value Optimization

This commit is contained in:
Alexey Prokhin
2011-09-13 12:01:51 +04:00
parent 0e754b5acd
commit 9a9999854f
6 changed files with 55 additions and 23 deletions

View File

@@ -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())

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);