[libcxx-commits] [PATCH] D59791: [pstl] Add a serial backend for the PSTL

Mikhail Dvorskiy via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 11 05:25:44 PDT 2019


MikeDvorskiy added inline comments.


================
Comment at: pstl/include/pstl/internal/parallel_backend_serial.h:106
+{
+    __leaf_merge(__first1, __last1, __first2, __last2, __out, __comp);
+}
----------------
ldionne wrote:
> MikeDvorskiy wrote:
> > ldionne wrote:
> > > Note that the obvious implementation doesn't work:
> > > 
> > > ```
> > > std::merge(__first1, __last1, __first2, __last2, __out, __comp);
> > > ```
> > > 
> > > because it requires the elements to be copyable, but pstl apparently expects the merge to only move elements around without copying them.
> > Why "doesnt work"?
> > 
> > In special case
> > ...
> >     if (__n <= __merge_cut_off)
> >     {
> >         // Fall back on serial merge
> >         __leaf_merge(__xs, __xe, __ys, __ye, __zs, __comp);
> >     }
> > ...
> > where __leaf_merge is std::merge
> Like I said, `std::merge` requires elements to be copyable, but the PSTL tests call `parallel_merge` with elements that are move-only. It also looks like you guys went through some hoops to make this work, see `__serial_move_merge` in `parallel_backend_utils.h`.
> 
> However, since it looks like calling `__leaf_merge` is a valid implementation, let's revisit this copyability issue at another point. I want to land this patch ASAP because other stuff depends on it.
> 
> 
> In case you're curious, the error message for copyability looks like this:
> ```
> <toolchain>/usr/include/c++/v1/algorithm:4392:23: error: object of type 'LocalWrapper<float>' cannot be assigned because its copy assignment operator is implicitly deleted
>             *__result = *__first2;
>                       ^
> <toolchain>/usr/include/c++/v1/algorithm:4416:19: note: in instantiation of function template specialization 'std::__1::__merge<std::__1::less<LocalWrapper<float> > &, std::__1::__wrap_iter<LocalWrapper<float> *>, std::__1::__wrap_iter<LocalWrapper<float> *>, LocalWrapper<float> *>' requested here
>     return _VSTD::__merge<_Comp_ref>(__first1, __last1, __first2, __last2, __result, __comp);
>                   ^
> <pstl-root>/include/pstl/internal/parallel_backend_serial.h:117:10: note: in instantiation of function template specialization 'std::__1::merge<std::__1::__wrap_iter<LocalWrapper<float> *>, std::__1::__wrap_iter<LocalWrapper<float> *>, LocalWrapper<float> *, std::__1::less<LocalWrapper<float> > >' requested here
>     std::merge(__first1, __last1, __first2, __last2, __out, __comp);
>          ^
> <pstl-root>/include/pstl/internal/algorithm_impl.h:2667:24: note: in instantiation of function template specialization '__pstl::__serial::__parallel_merge<const __pstl::execution::v1::parallel_policy &, std::__1::__wrap_iter<LocalWrapper<float> *>, std::__1::__wrap_iter<LocalWrapper<float> *>, LocalWrapper<float> *, std::__1::less<LocalWrapper<float> >, (lambda at <pstl-root>/include/pstl/internal/algorithm_impl.h:2669:13)>' requested here
>         __par_backend::__parallel_merge(
>                        ^
> <pstl-root>/include/pstl/internal/glue_algorithm_impl.h:899:17: note: in instantiation of function template specialization '__pstl::__internal::__pattern_inplace_merge<const __pstl::execution::v1::parallel_policy &, std::__1::__wrap_iter<LocalWrapper<float> *>, std::__1::less<LocalWrapper<float> >, std::__1::integral_constant<bool, false> >' requested here
>     __internal::__pattern_inplace_merge(
>                 ^
> <pstl-root>/test/std/algorithms/alg.merge/inplace_merge.pass.cpp:63:14: note: in instantiation of function template specialization 'std::inplace_merge<const __pstl::execution::v1::parallel_policy &, std::__1::__wrap_iter<LocalWrapper<float> *>, std::__1::less<LocalWrapper<float> > >' requested here
>         std::inplace_merge(exec, first2, mid2, last2, comp);
>              ^
> <pstl-root>/test/support/utils.h:757:9: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
>         op(std::forward<Rest>(rest)...);
>         ^
> ...
> ```
> 
1. Yes, std::merge requires "copyable".

Actually, the all "move" operations  in "__serial_move_merge"  will reduce to "copy" operations If "move" semantic is not specified.

But, you are right. If we pass non-const iterator into std::merge and a value type has the non-trivial move semantic we have got wrong effect... 
It may be quickly  fixed in "__parallel_merge". I'll do it. 

2. But the compiler diagnostic shown here tells about "std::inplace_merge" algo. This algo requires just move semantic and the test checks it.
The problem is that __pattern_inplace_merge re-uses  __par_backend::__parallel_merge due to there is no a special __par_backend::__parallel__inplace_merge API. I think it makes sense to add __par_backend::__parallel__inplace_merge API (and move the relevant code from __pattern_inplace_merge into __par_backend). I'll do it. After that in your serial back-end you should just call std::inplace_merge serial. 

Thanks for raising the issues.




Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D59791





More information about the libcxx-commits mailing list