aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2021-07-03 02:42:14 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-07-03 13:00:56 +0200
commit152f4d0e4d3b524ce30d05f20e23a44b0dd29765 (patch)
tree305b63554a1557882c9258852a71e97706044670 /gcc
parent7a60a6e8b36dec960939494baef0f1f15dbfc450 (diff)
downloadgcc-152f4d0e4d3b524ce30d05f20e23a44b0dd29765.zip
gcc-152f4d0e4d3b524ce30d05f20e23a44b0dd29765.tar.gz
gcc-152f4d0e4d3b524ce30d05f20e23a44b0dd29765.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/d/toir.cc32
-rw-r--r--gcc/testsuite/gdc.dg/torture/pr101273.d39
2 files changed, 69 insertions, 2 deletions
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 <retval>); */
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);
+}