mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 09:00:33 +03:00
Fix DMD Issue 11394 - NRVO should work for object field initialization in constructor
This commit is contained in:
parent
1e649422d6
commit
61979387fd
6 changed files with 58 additions and 33 deletions
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
12
gen/toir.cpp
12
gen/toir.cpp
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue