[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

Evgeny Shulgin via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 14 15:48:05 PST 2022


Izaron added a comment.

There is a nice proposal (P2025) Guaranteed copy elision for return variables <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2025r2.html> by **Anton Zhilin**. The poll on the proposal showed that its ideas are very welcome: link to cplusplus/papers github <https://github.com/cplusplus/papers/issues/756#issuecomment-845364557>. Although the proposal is not yet accepted into the Standard in its current wording, some ideas are still good and can be implemented "in advance".

> This proposal aims to provide guaranteed copy elision for common cases of local variables being returned from a function, a.k.a. "guaranteed NRVO".

С++ сompiler implementations determine by their own rules whether there will be a NRVO (since it is not a required optimization). The proposal contains a collection of common cases of local variables being returned where copy elision is safe and makes senses and therefore is desirable to do.

The main requirement (omitting details for language-lawyers) is that:

> Copy elision is guaranteed for return x; if every return "seen" by x is return x;

"seen by `x`" means here "all non-discarded return statements in `x`'s potential scope". There are more details in the proposal.

The collection of common cases contains 20 examples: §4.1. Examples <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2025r2.html#examples>.
Here is the current status of these examples:

- [OK] 13 out of 20 examples are working in Clang as expected.
- [FAIL] 13th example: should be considered separately (as part of fixing consteval code)
- [FAIL] 14th example: should be considered separately (as I haven't looked yet how `CXXCatchStmt` works).
- [FAIL] 18th example: is unfixable now because of Clang's architecture: my comment on the issue <https://github.com/llvm/llvm-project/issues/50297#issuecomment-1033059593>.
- **[OK with the patch]** 7th, 8th, 11th, 15th example: are working with this patch.

In order to make the last group of 4 examples working, there is a need to rewrite the logic for calculating the NRVO candidate.
The `clang::Scope` class has methods `void AddDecl(Decl *D)`, `void addNRVOCandidate(VarDecl *VD)`, `void setNoNRVO()`, that are called in the order of the scope's parsing.

- `void AddDecl(Decl *D)` is called when there is a new `Decl *D` in the scope. The `D`'s potential scope starts now.
- `void addNRVOCandidate(VarDecl *VD)` is called when there is a `return <named-variable>` in the scope or when a children scope has successfully calculated its single NRVO candidate.
- `void setNoNRVO()` is called when there is a `return <not-a-named-var>` in the scope or when a children scope is telling us to drop our NRVO candidates (nevertheless, the children scope now can still succesfully calculated the NRVO candidate).

We need to have a set of "unspoiled variables" to find the NRVO candidate effectively (yeah, introducing some made up terminology...) A variable is "unspoiled" if it is not forbidden to be the NRVO candidate yet. An `AddDecl` call adds the variable to this set. An `addNRVOCandidate` call "spoils" every variable except `VD`. A `setNoNRVO` "spoils" every variable. Only an "unspoiled variable" may be the NRVO candidate.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792



More information about the cfe-commits mailing list