mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-26 00:23:14 +01:00
Named Return Value Optimization
This commit is contained in:
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user