Skip to content

exec(fork_join): coalesce empty and unary calls - #2302

Open
romintomasetti wants to merge 4 commits into
NVIDIA:mainfrom
romintomasetti:fork-join-p4269
Open

romintomasetti wants to merge 4 commits into
NVIDIA:mainfrom
romintomasetti:fork-join-p4269

Conversation

@romintomasetti

@romintomasetti romintomasetti commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor
  • When exec::fork_join(sndr, clsr) is given a single closure, do no attempt to wrap it in the (thereby useless) fork_join machinery. Return sndr | clsr.
  • When exec::fork_join(sndr) is given no closure, it behaves like sndr.

As a drive-by, I've added a few noexcept to then.

Similar to:

See P4269R1.

@copy-pr-bot

copy-pr-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@romintomasetti

Copy link
Copy Markdown
Contributor Author

@RobertLeahy @ericniebler Could you please have a look? Thanks!

Comment thread include/exec/fork_join.hpp Outdated
Comment thread include/exec/fork_join.hpp
Comment thread include/exec/fork_join.hpp Outdated
Comment thread include/exec/fork_join.hpp Outdated
Comment thread test/stdexec/algos/adaptors/test_then.cpp
Comment thread test/exec/test_fork_join.cpp Outdated
Comment thread include/stdexec/__detail/__then.hpp Outdated
Comment thread test/exec/test_fork_join.cpp Outdated
Comment thread include/stdexec/__detail/__then.hpp Outdated
@ericniebler

Copy link
Copy Markdown
Collaborator

needs a clang-format

@ericniebler

Copy link
Copy Markdown
Collaborator

/ok to test a463493

@romintomasetti

Copy link
Copy Markdown
Contributor Author

We still need to fix the fork_join reports failures while caching results test. It's using a single branch (closure), so with this PR it's failing. I'll add a dummy branch.

@romintomasetti

Copy link
Copy Markdown
Contributor Author

@ericniebler I'm not sure why this hasn't been detected earlier, but I had to modify how the fork_join cache variant alternatives are computed to account for potentially throwing decay-copied values:

STDEXEC_TRY
{
using _tuple_t = STDEXEC::__decayed_tuple<Tag, Args...>;
_cache_.template emplace<_tuple_t>(Tag{}, static_cast<Args&&>(args)...);
}
STDEXEC_CATCH_ALL
{
if constexpr (!STDEXEC::__nothrow_decay_copyable<Args...>)
{
using _tuple_t = STDEXEC::__tuple<STDEXEC::set_error_t, ::std::exception_ptr>;
_cache_.template emplace<_tuple_t>(STDEXEC::set_error, ::std::current_exception());
}
}

@romintomasetti
romintomasetti force-pushed the fork-join-p4269 branch 2 times, most recently from e171696 to 137e8fd Compare October 10, 2026 12:47
@ericniebler

Copy link
Copy Markdown
Collaborator

/ok to test 137e8fd

@romintomasetti

romintomasetti commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Seems on MSVC my test did not work. I'll investigate on Monday. @maartenarnst Any though?

CHECK( counter::move_constructions == 1 )
2026-10-10T16:13:23.9274470Z 712: with expansion:
2026-10-10T16:13:23.9275435Z 712:   0 == 1

Edit: Since the atomic increments are observable behavior, I tend to think that MSVC is not standard-conforming in this case. So probably best to opt for an ifdef(MSVC) test.

@maartenarnst

Copy link
Copy Markdown
Contributor

Seems on MSVC my test did not work. I'll investigate on Monday. @maartenarnst Any though?

I think your test is correct. The assertions together show that we take the value path and a counter reference is passed.

Edit: Since the atomic increments are observable behavior, I tend to think that MSVC is not standard-conforming in this case. So probably best to opt for an ifdef(MSVC) test.

Confirmed! It looks like MSVC optimises away the move when it stores the object in the __tuple. It seems the issue arises when the object is empty and the tuple's members are annotated with "no unique address". This is a reproducer:

https://godbolt.org/z/cG81sYxfo

When we add a member in the counter class or remove the "no unique address", the move appears. So the issue seems harmless in practice.

Claude (Anthropic) helped with the analysis.

@ericniebler

ericniebler commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

This is a reproducer:
https://godbolt.org/z/cG81sYxfo

a slight tweak of the reproducer causes the latest MSVC to ICE.
https://godbolt.org/z/vM1x3s693

i've filed that bug here:
https://developercommunity.microsoft.com/t/MSVC-compiler-hits-C1001-with-msvc::no/11164060

the right fix may be to give up trying to use [[msvc::no_unique_address]].

EDIT: this looks related: https://developercommunity.microsoft.com/t/11160652

@romintomasetti

Copy link
Copy Markdown
Contributor Author

Should we just modify the test to something like this? It is clearly a compiler compliance issue that affects just this test, so I would put too much science into it and move on.

#ifdef(MSVC)
// see report of Eric
CHECK(count.move == 0);
#else
CHECK(count.move ==1);
#endif

romintomasetti and others added 3 commits October 12, 2026 06:46
Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>
Similar to NVIDIA#2124. See  P4269R1.

Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>
Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>
@maartenarnst

Copy link
Copy Markdown
Contributor

I've just filed the bug for the move constructor too:
https://developercommunity.visualstudio.com/t/MSVC-skips-move-constructor-for-empty-/11164256

I've mentioned the bug report that @ericniebler had already filed and the related bug report.

@ericniebler

Copy link
Copy Markdown
Collaborator

/ok to test 39c73f0

Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants