Skip to content

Commit

Permalink
Move checkNRVO() from func.d to funcsem.d (#16536)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Muscar <alex@muscar.eu>
  • Loading branch information
muscar and Alex Muscar authored Jun 1, 2024
1 parent e9a3680 commit 4de90c7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 52 deletions.
52 changes: 0 additions & 52 deletions compiler/src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -1557,58 +1557,6 @@ extern (C++) class FuncDeclaration : Declaration
return fd;
}

/***********************************************
* Check all return statements for a function to verify that returning
* using NRVO is possible.
*
* Returns:
* `false` if the result cannot be returned by hidden reference.
*/
extern (D) final bool checkNRVO()
{
if (!isNRVO() || returns is null)
return false;

auto tf = type.toTypeFunction();
if (tf.isref)
return false;

foreach (rs; *returns)
{
if (auto ve = rs.exp.isVarExp())
{
auto v = ve.var.isVarDeclaration();
if (!v || v.isReference())
return false;
else if (nrvo_var is null)
{
// Variables in the data segment (e.g. globals, TLS or not),
// parameters and closure variables cannot be NRVOed.
if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
return false;
if (v.nestedrefs.length && needsClosure())
return false;
// don't know if the return storage is aligned
version (MARS)
{
if (alignSectionVars && (*alignSectionVars).contains(v))
return false;
}
// The variable type needs to be equivalent to the return type.
if (!v.type.equivalent(tf.next))
return false;
//printf("Setting nrvo to %s\n", v.toChars());
nrvo_var = v;
}
else if (nrvo_var != v)
return false;
}
else //if (!exp.isLvalue()) // keep NRVO-ability
return false;
}
return true;
}

override final inout(FuncDeclaration) isFuncDeclaration() inout
{
return this;
Expand Down
56 changes: 56 additions & 0 deletions compiler/src/dmd/funcsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ import dmd.tokens;
import dmd.typesem;
import dmd.visitor;

version (IN_GCC) {}
else version (IN_LLVM) {}
else version = MARS;

/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
*/
extern (C++) final class NrvoWalker : StatementRewriteWalker
Expand Down Expand Up @@ -3006,3 +3010,55 @@ extern (D) void checkMain(FuncDeclaration fd)
if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
.error(fd.loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", fd.kind, fd.toPrettyChars, tf.nextOf().toChars());
}

/***********************************************
* Check all return statements for a function to verify that returning
* using NRVO is possible.
*
* Returns:
* `false` if the result cannot be returned by hidden reference.
*/
extern (D) bool checkNRVO(FuncDeclaration fd)
{
if (!fd.isNRVO() || fd.returns is null)
return false;

auto tf = fd.type.toTypeFunction();
if (tf.isref)
return false;

foreach (rs; *fd.returns)
{
if (auto ve = rs.exp.isVarExp())
{
auto v = ve.var.isVarDeclaration();
if (!v || v.isReference())
return false;
else if (fd.nrvo_var is null)
{
// Variables in the data segment (e.g. globals, TLS or not),
// parameters and closure variables cannot be NRVOed.
if (v.isDataseg() || v.isParameter() || v.toParent2() != fd)
return false;
if (v.nestedrefs.length && fd.needsClosure())
return false;
// don't know if the return storage is aligned
version (MARS)
{
if (fd.alignSectionVars && (*fd.alignSectionVars).contains(v))
return false;
}
// The variable type needs to be equivalent to the return type.
if (!v.type.equivalent(tf.next))
return false;
//printf("Setting nrvo to %s\n", v.toChars());
fd.nrvo_var = v;
}
else if (fd.nrvo_var != v)
return false;
}
else //if (!exp.isLvalue()) // keep NRVO-ability
return false;
}
return true;
}

0 comments on commit 4de90c7

Please sign in to comment.