d: Missed RVO optimization with non-POD structs
The D front-end semantic pass sometimes declares a temporary inside a return expression. This is now detected with the RESULT_DECL replacing the temporary, allowing for RVO to be done. PR d/101273 gcc/d/ChangeLog: * toir.cc (IRVisitor::visit (ReturnStatement *)): Detect returns that use a temporary, and replace with return value. gcc/testsuite/ChangeLog: * gdc.dg/torture/pr101273.d: New test. (cherry picked from commit 152f4d0e4d3b524ce30d05f20e23a44b0dd29765)
This commit is contained in:
parent
a4f5e3962f
commit
46d1cb4c21
@ -1034,14 +1034,37 @@ public:
|
||||
/* Detect a call to a constructor function, or if returning a struct
|
||||
literal, write result directly into the return value. */
|
||||
StructLiteralExp *sle = NULL;
|
||||
bool using_rvo_p = false;
|
||||
|
||||
if (DotVarExp *dve = (s->exp->op == TOKcall
|
||||
&& s->exp->isCallExp ()->e1->op == TOKdotvar
|
||||
? s->exp->isCallExp ()->e1->isDotVarExp ()
|
||||
: NULL))
|
||||
{
|
||||
sle = (dve->var->isCtorDeclaration ()
|
||||
? dve->e1->isStructLiteralExp () : NULL);
|
||||
if (dve->var->isCtorDeclaration ())
|
||||
{
|
||||
if (CommaExp *ce = dve->e1->isCommaExp ())
|
||||
{
|
||||
/* Temporary initialized inside a return expression, and
|
||||
used as the return value. Replace it with the hidden
|
||||
reference to allow RVO return. */
|
||||
DeclarationExp *de = ce->e1->isDeclarationExp ();
|
||||
VarExp *ve = ce->e2->isVarExp ();
|
||||
if (de != NULL && ve != NULL
|
||||
&& ve->var == de->declaration
|
||||
&& ve->var->storage_class & STCtemp)
|
||||
{
|
||||
tree var = get_symbol_decl (ve->var);
|
||||
TREE_ADDRESSABLE (var) = 1;
|
||||
SET_DECL_VALUE_EXPR (var, decl);
|
||||
DECL_HAS_VALUE_EXPR_P (var) = 1;
|
||||
SET_DECL_LANG_NRVO (var, this->func_->shidden);
|
||||
using_rvo_p = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
sle = dve->e1->isStructLiteralExp ();
|
||||
}
|
||||
}
|
||||
else
|
||||
sle = s->exp->isStructLiteralExp ();
|
||||
@ -1050,11 +1073,16 @@ public:
|
||||
{
|
||||
StructDeclaration *sd = type->baseElemOf ()->isTypeStruct ()->sym;
|
||||
sle->sym = build_address (this->func_->shidden);
|
||||
using_rvo_p = true;
|
||||
|
||||
/* Fill any alignment holes in the return slot using memset. */
|
||||
if (!identity_compare_p (sd) || sd->isUnionDeclaration ())
|
||||
add_stmt (build_memset_call (this->func_->shidden));
|
||||
}
|
||||
|
||||
if (using_rvo_p == true)
|
||||
{
|
||||
/* Generate: (expr, return <retval>); */
|
||||
add_stmt (build_expr_dtor (s->exp));
|
||||
}
|
||||
else
|
||||
|
39
gcc/testsuite/gdc.dg/torture/pr101273.d
Normal file
39
gcc/testsuite/gdc.dg/torture/pr101273.d
Normal file
@ -0,0 +1,39 @@
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101273
|
||||
// { dg-do run }
|
||||
|
||||
struct S101273
|
||||
{
|
||||
int x;
|
||||
S101273* impl;
|
||||
this(int x)
|
||||
{
|
||||
this.x = x;
|
||||
this.impl = &this;
|
||||
}
|
||||
~this() { }
|
||||
}
|
||||
|
||||
S101273 makeS101273()
|
||||
{
|
||||
return S101273(2);
|
||||
}
|
||||
|
||||
S101273 nrvo101273()
|
||||
{
|
||||
S101273 ret = makeS101273();
|
||||
return ret;
|
||||
}
|
||||
|
||||
S101273 rvo101273()
|
||||
{
|
||||
return makeS101273();
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
auto nrvo = nrvo101273();
|
||||
assert(&nrvo is nrvo.impl);
|
||||
|
||||
auto rvo = rvo101273();
|
||||
assert(&rvo is rvo.impl);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user