Fix DMD Issue 11394 - NRVO should work for object field initialization in constructor

This commit is contained in:
Alexey Prokhin 2014-06-27 13:17:56 +04:00
parent 1e649422d6
commit 61979387fd
6 changed files with 58 additions and 33 deletions

View file

@ -1112,6 +1112,19 @@ void DtoVarDeclaration(VarDeclaration* vd)
else {
vd->ir.irLocal = new IrLocal(vd);
Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type;
llvm::Value* allocainst;
LLType* lltype = DtoType(type);
if(gDataLayout->getTypeSizeInBits(lltype) == 0)
allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype));
else
allocainst = DtoAlloca(type, vd->toChars());
vd->ir.irLocal->value = allocainst;
gIR->DBuilder.EmitLocalVariable(allocainst, vd);
/* NRVO again:
T t = f(); // t's memory address is taken hidden pointer
*/
@ -1131,42 +1144,23 @@ void DtoVarDeclaration(VarDeclaration* vd)
rhs = static_cast<CastExp *>(rhs)->e1;
if (rhs->op == TOKcall) {
CallExp *ce = static_cast<CallExp *>(rhs);
TypeFunction *tf = static_cast<TypeFunction *>(ce->e1->type->toBasetype());
if (tf->ty == Tfunction && tf->linkage != LINKintrinsic) {
gABI->newFunctionType(tf);
bool retInArg = gABI->returnInArg(tf);
gABI->doneWithFunctionType();
if (retInArg) {
if (DtoIsReturnInArg(ce->e1->type))
{
if (isSpecialRefVar(vd))
{
LLValue* const val = ce->toElem(gIR)->getLVal();
if (isSpecialRefVar(vd))
{
vd->ir.irLocal->value = DtoAlloca(
vd->type->pointerTo(), vd->toChars());
DtoStore(val, vd->ir.irLocal->value);
}
else
{
vd->ir.irLocal->value = val;
}
return;
DtoStore(val, vd->ir.irLocal->value);
}
else
{
DValue* fnval = ce->e1->toElem(gIR);
DtoCallFunction(ce->loc, ce->type, fnval, ce->arguments, vd->ir.irLocal->value);
}
return;
}
}
}
}
Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type;
llvm::Value* allocainst;
LLType* lltype = DtoType(type);
if(gDataLayout->getTypeSizeInBits(lltype) == 0)
allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype));
else
allocainst = DtoAlloca(type, vd->toChars());
vd->ir.irLocal->value = allocainst;
gIR->DBuilder.EmitLocalVariable(allocainst, vd);
}
IF_LOG Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n';

View file

@ -207,7 +207,7 @@ void DtoBuildDVarArgList(std::vector<LLValue*>& args, std::vector<llvm::Attribut
#endif
///
DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments);
DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments, LLValue* retvar = 0);
Type* stripModifiers(Type* type);

View file

@ -326,7 +326,7 @@ void DtoBuildDVarArgList(std::vector<LLValue*>& args,
// FIXME: this function is a mess !
DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments)
DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments, llvm::Value *retvar)
{
IF_LOG Logger::println("DtoCallFunction()");
LOG_SCOPE
@ -390,7 +390,8 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
// return in hidden ptr is first
if (retinptr)
{
LLValue* retvar = DtoRawAlloca((*argiter)->getContainedType(0), resulttype->alignsize(), ".rettmp");
if (!retvar)
retvar = DtoRawAlloca((*argiter)->getContainedType(0), resulttype->alignsize(), ".rettmp");
++argiter;
args.push_back(retvar);

View file

@ -530,6 +530,18 @@ DValue* AssignExp::toElem(IRState* p)
}
}
// NRVO for object field initialization in constructor
if (op == TOKconstruct && e2->op == TOKcall)
{
CallExp *ce = static_cast<CallExp *>(e2);
if (DtoIsReturnInArg(ce->e1->type))
{
DValue* fnval = ce->e1->toElem(p);
LLValue *lval = e1->toElem(p)->getLVal();
return DtoCallFunction(ce->loc, ce->type, fnval, ce->arguments, lval);
}
}
DValue* l = e1->toElem(p);
DValue* r = e2->toElem(p);

View file

@ -14,6 +14,7 @@
#include "id.h"
#include "init.h"
#include "module.h"
#include "gen/abi.h"
#include "gen/arrays.h"
#include "gen/classes.h"
#include "gen/complex.h"
@ -40,6 +41,19 @@ bool DtoIsPassedByRef(Type* type)
return (t == Tstruct || t == Tsarray);
}
bool DtoIsReturnInArg(Type *type)
{
TypeFunction *tf = static_cast<TypeFunction *>(type->toBasetype());
if (tf->ty == Tfunction && tf->linkage != LINKintrinsic)
{
gABI->newFunctionType(tf);
bool retInArg = gABI->returnInArg(tf);
gABI->doneWithFunctionType();
return retInArg;
}
return false;
}
#if LDC_LLVM_VER >= 303
llvm::Attribute::AttrKind DtoShouldExtend(Type* type)
#elif LDC_LLVM_VER == 302

View file

@ -39,6 +39,10 @@ LLType* i1ToI8(LLType* t);
// returns true if the type must be passed by pointer
bool DtoIsPassedByRef(Type* type);
// returns true if the type is a function and
// the return value is passed in a register
bool DtoIsReturnInArg(Type *type);
// should argument be zero or sign extended
#if LDC_LLVM_VER >= 303
llvm::Attribute::AttrKind DtoShouldExtend(Type* type);