From: Iain Buclaw Date: Sat, 3 Jul 2021 00:42:14 +0000 (+0200) Subject: d: Missed RVO optimization with non-POD structs X-Git-Tag: upstream/12.2.0~6702 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=152f4d0e4d3b524ce30d05f20e23a44b0dd29765;p=platform%2Fupstream%2Fgcc.git 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. --- diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index 41d07a7..eaee6f7 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -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 ); */ add_stmt (build_expr_dtor (s->exp)); } else diff --git a/gcc/testsuite/gdc.dg/torture/pr101273.d b/gcc/testsuite/gdc.dg/torture/pr101273.d new file mode 100644 index 0000000..e300e03 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/pr101273.d @@ -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); +}