public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* transform-reduce compiling with seq but not par - bug?
@ 2020-12-18 22:33 Kai
  2020-12-18 22:49 ` Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: Kai @ 2020-12-18 22:33 UTC (permalink / raw)
  To: gcc-help

Morning!

I've got a transform-reduce statement that compiles with execution::seq.
When replacing the policy parameter with execution::par, I get a compile
time error. This seems odd to me and I'm seeking advice here whether to
file a bug report with gcc or not.

The environment is a gcc 10.2 on an arch linux derivate; libstdc++ has
version 6.0.28 (owned by package gcc-libs 10.2.0-3); libtbb is in use
(owned by package tbb 2020.3-1).

The statement in questions reads (in a simplified example):
Obj x = transform_reduce( execution::par, v.begin(), v.end(), Obj{0},
                          [](Obj &a,Obj const &b) { a.combine(b); return
move(a); },
                          [](int i){ return Obj{i}; }  );

( overload 6: https://en.cppreference.com/w/cpp/algorithm/transform_reduce )

Pls find the compiler error at the end of this mail; seems to be in the
interface to TBB. On the compiler explorer, this behaviour is
reproducible, when TBB is selected as additional library. It compiles
(and runs) OK there without the TBB.
Might this be a bug in gcc's interface to TBB?

The complete compiler error messages follows (different name "Inte" for
example class). (If requested I can, of course, post a complete source
for the problem as well.)

Cheers, Kai

In file included from /usr/include/c++/10.2.0/pstl/parallel_backend.h:16,
                 from /usr/include/c++/10.2.0/pstl/algorithm_impl.h:22,
                 from /usr/include/c++/10.2.0/pstl/glue_execution_defs.h:50,
                 from /usr/include/c++/10.2.0/execution:32,
                 from ../demos/main.cpp:3:
/usr/include/c++/10.2.0/pstl/parallel_backend_tbb.h: In instantiation of
‘void __pstl::__par_backend::__par_trans_red_body<_Index, _Up, _Tp, _Cp,
_Rp>::operator()(const tbb::blocked_range<Index>&) [with _Index =
__gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Up =
__pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >)>; _Tp = Inte; _Cp = main(int,
char**)::<lambda(Inte&, const Inte&)>; _Rp =
__pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __gnu_cxx::__normal_iterator<int*, std::vector<int>
>, Inte)>]’:
/usr/include/tbb/parallel_reduce.h:150:47:   required from ‘void
tbb::interface9::internal::start_reduce<Range, Body,
Partitioner>::run_body(Range&) [with Range =
tbb::blocked_range<__gnu_cxx::__normal_iterator<int*, std::vector<int> >
>; Body =
__pstl::__par_backend::__par_trans_red_body<__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >)>, Inte, main(int, char**)::<lambda(Inte&, const
Inte&)>, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __gnu_cxx::__normal_iterator<int*, std::vector<int>
>, Inte)> >; Partitioner = const tbb::auto_partitioner]’
/usr/include/tbb/partitioner.h:423:27:   required from ‘void
tbb::interface9::internal::dynamic_grainsize_mode<Mode>::work_balance(StartType&,
Range&) [with StartType =
tbb::interface9::internal::start_reduce<tbb::blocked_range<__gnu_cxx::__normal_iterator<int*,
std::vector<int> > >,
__pstl::__par_backend::__par_trans_red_body<__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >)>, Inte, main(int, char**)::<lambda(Inte&, const
Inte&)>, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __gnu_cxx::__normal_iterator<int*, std::vector<int>
>, Inte)> >, const tbb::auto_partitioner>; Range =
tbb::blocked_range<__gnu_cxx::__normal_iterator<int*, std::vector<int> >
>; Mode =
tbb::interface9::internal::adaptive_mode<tbb::interface9::internal::auto_partition_type>]’
/usr/include/tbb/partitioner.h:256:28:   required from ‘void
tbb::interface9::internal::partition_type_base<Partition>::execute(StartType&,
Range&) [with StartType =
tbb::interface9::internal::start_reduce<tbb::blocked_range<__gnu_cxx::__normal_iterator<int*,
std::vector<int> > >,
__pstl::__par_backend::__par_trans_red_body<__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >)>, Inte, main(int, char**)::<lambda(Inte&, const
Inte&)>, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __gnu_cxx::__normal_iterator<int*, std::vector<int>
>, Inte)> >, const tbb::auto_partitioner>; Range =
tbb::blocked_range<__gnu_cxx::__normal_iterator<int*, std::vector<int> >
>; Partition = tbb::interface9::internal::auto_partition_type]’
/usr/include/tbb/parallel_reduce.h:190:29:   required from ‘tbb::task*
tbb::interface9::internal::start_reduce<Range, Body,
Partitioner>::execute() [with Range =
tbb::blocked_range<__gnu_cxx::__normal_iterator<int*, std::vector<int> >
>; Body =
__pstl::__par_backend::__par_trans_red_body<__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >)>, Inte, main(int, char**)::<lambda(Inte&, const
Inte&)>, __pstl::__internal::__pattern_transform_reduce<const
__pstl::execution::v1::parallel_policy&,
__gnu_cxx::__normal_iterator<int*, std::vector<int> >, Inte, main(int,
char**)::<lambda(Inte&, const Inte&)>, main(int, char**)::<lambda(int)>,
std::integral_constant<bool, false>
>::<lambda()>::<lambda(__gnu_cxx::__normal_iterator<int*,
std::vector<int> >, __gnu_cxx::__normal_iterator<int*, std::vector<int>
>, Inte)> >; Partitioner = const tbb::auto_partitioner]’
/usr/include/tbb/parallel_reduce.h:181:11:   required from here
/usr/include/c++/10.2.0/pstl/parallel_backend_tbb.h:177:31: error: no
match for call to ‘(main(int, char**)::<lambda(Inte&, const Inte&)>)
(Inte, Inte)’
  177 |                 _Tp(_M_combine(_M_u(__i), _M_u(__i + 1))); //
The condition i+1 < j is provided by the grain size of 3
      |                     ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/10.2.0/pstl/parallel_backend_tbb.h:177:31: note:
candidate: ‘Inte (*)(Inte&, const Inte&)’ (conversion)
/usr/include/c++/10.2.0/pstl/parallel_backend_tbb.h:177:31: note:
conversion of argument 2 would be ill-formed:
/usr/include/c++/10.2.0/pstl/parallel_backend_tbb.h:177:36: error:
cannot bind non-const lvalue reference of type ‘Inte&’ to an rvalue of
type ‘Inte’
  177 |                 _Tp(_M_combine(_M_u(__i), _M_u(__i + 1))); //
The condition i+1 < j is provided by the grain size of 3
      |                                ~~~~^~~~~
../demos/main.cpp:41:34: note: candidate: ‘main(int,
char**)::<lambda(Inte&, const Inte&)>’ (near match)
   41 |                                  [](Inte &a,Inte const &b) /*->
Inte*/ { a.combine(b); return move(a); },
      |                                  ^
../demos/main.cpp:41:34: note:   conversion of argument 1 would be
ill-formed:
In file included from /usr/include/c++/10.2.0/pstl/parallel_backend.h:16,
                 from /usr/include/c++/10.2.0/pstl/algorithm_impl.h:22,
                 from /usr/include/c++/10.2.0/pstl/glue_execution_defs.h:50,
                 from /usr/include/c++/10.2.0/execution:32,
                 from ../demos/main.cpp:3:
/usr/include/c++/10.2.0/pstl/parallel_backend_tbb.h:177:36: error:
cannot bind non-const lvalue reference of type ‘Inte&’ to an rvalue of
type ‘Inte’
  177 |                 _Tp(_M_combine(_M_u(__i), _M_u(__i + 1))); //
The condition i+1 < j is provided by the grain size of 3
      |                                ~~~~^~~~~

--
"They have the ultimate solution to all the problems that we face
 It's pointing rockets at the russians and hope they don't end up in greece"
                                                           <Fisher-Z>
D-55120 Meenz
++ PGP Key fingerprint  059D 4FAA FE93 5928 1B22  7FAF EC08 5BF9 D50E
F933 ++
-----BEGIN GEEK CODE BLOCK-----
VERSION: 3.12
GCS/IT d- s: a++>-----(?) C++$ UL++(++++$) P++ L++$ E-(+) W--(+) N !w---
!O !M V? PS+ PE-() Y+ PGP++ t R@* tv--(-) b+>++ DI++ G e+++(*) h? y?
------END GEEK CODE BLOCK------

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: transform-reduce compiling with seq but not par - bug?
  2020-12-18 22:33 transform-reduce compiling with seq but not par - bug? Kai
@ 2020-12-18 22:49 ` Jonathan Wakely
  2020-12-18 23:41   ` Kai
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2020-12-18 22:49 UTC (permalink / raw)
  To: Kai; +Cc: gcc-help

On Fri, 18 Dec 2020, 22:35 Kai via Gcc-help, <gcc-help@gcc.gnu.org> wrote:

> Morning!
>
> I've got a transform-reduce statement that compiles with execution::seq.
> When replacing the policy parameter with execution::par, I get a compile
> time error. This seems odd to me and I'm seeking advice here whether to
> file a bug report with gcc or not.
>
> The environment is a gcc 10.2 on an arch linux derivate; libstdc++ has
> version 6.0.28 (owned by package gcc-libs 10.2.0-3); libtbb is in use
> (owned by package tbb 2020.3-1).
>
> The statement in questions reads (in a simplified example):
> Obj x = transform_reduce( execution::par, v.begin(), v.end(), Obj{0},
>                           [](Obj &a,Obj const &b) { a.combine(b); return
> move(a); },
>                           [](int i){ return Obj{i}; }  );
>
> ( overload 6: https://en.cppreference.com/w/cpp/algorithm/transform_reduce
> )
>
> Pls find the compiler error at the end of this mail; seems to be in the
> interface to TBB. On the compiler explorer, this behaviour is
> reproducible, when TBB is selected as additional library. It compiles
> (and runs) OK there without the TBB.
> Might this be a bug in gcc's interface to TBB?
>


No, I don't think this is a bug in GCC. Your unary_op returns by value,
which means it cannot be the first argument for your binary_op, because
that requires a non-const lvalue.

It should work if you change your first lambda to:

[](Obj a,Obj const &b) { a.combine(b); return a; }


>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: transform-reduce compiling with seq but not par - bug?
  2020-12-18 22:49 ` Jonathan Wakely
@ 2020-12-18 23:41   ` Kai
  2020-12-19 10:32     ` Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: Kai @ 2020-12-18 23:41 UTC (permalink / raw)
  To: gcc-help

On 18/12/2020 23:49, Jonathan Wakely wrote:
> On Fri, 18 Dec 2020, 22:35 Kai via Gcc-help, <gcc-help@gcc.gnu.org
> <mailto:gcc-help@gcc.gnu.org>> wrote:
>>
>>     The statement in questions reads (in a simplified example):
>>     Obj x = transform_reduce( execution::par, v.begin(), v.end(), Obj{0},
>>                               [](Obj &a,Obj const &b) { a.combine(b);
return
>>     move(a); },
>>                               [](int i){ return Obj{i}; }  );
>>
> No, I don't think this is a bug in GCC. Your unary_op returns by value,
> which means it cannot be the first argument for your binary_op, because
> that requires a non-const lvalue.
>
> It should work if you change your first lambda to:
>
> [](Obj a,Obj const &b) { a.combine(b); return a; }

Thanks for your quick response. Sure, taking that arg by value works.
But my initial intention was to avoid copying of objects (they might
become large) as much as possible, thus passing by reference or moving.
As I wrote, the statement compiles (and works) when policy is
execution::seq - which strikes me as odd...

Cheers, Kai
--
"Rest your weary head and let your heart decide"
<Queen>
D-55120 Meenz
++ PGP Key fingerprint  059D 4FAA FE93 5928 1B22  7FAF EC08 5BF9 D50E
F933 ++
-----BEGIN GEEK CODE BLOCK-----
VERSION: 3.12
GCS/IT d- s: a++>-----(?) C++$ UL++(++++$) P++ L++$ E-(+) W--(+) N !w---
!O !M V? PS+ PE-() Y+ PGP++ t R@* tv--(-) b+>++ DI++ G e+++(*) h? y?
------END GEEK CODE BLOCK------

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: transform-reduce compiling with seq but not par - bug?
  2020-12-18 23:41   ` Kai
@ 2020-12-19 10:32     ` Jonathan Wakely
  2020-12-19 21:40       ` Kai
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2020-12-19 10:32 UTC (permalink / raw)
  To: Kai; +Cc: gcc-help

On Fri, 18 Dec 2020, 23:42 Kai via Gcc-help, <gcc-help@gcc.gnu.org> wrote:

> On 18/12/2020 23:49, Jonathan Wakely wrote:
> > On Fri, 18 Dec 2020, 22:35 Kai via Gcc-help, <gcc-help@gcc.gnu.org
> > <mailto:gcc-help@gcc.gnu.org>> wrote:
> >>
> >>     The statement in questions reads (in a simplified example):
> >>     Obj x = transform_reduce( execution::par, v.begin(), v.end(),
> Obj{0},
> >>                               [](Obj &a,Obj const &b) { a.combine(b);
> return
> >>     move(a); },
> >>                               [](int i){ return Obj{i}; }  );
> >>
> > No, I don't think this is a bug in GCC. Your unary_op returns by value,
> > which means it cannot be the first argument for your binary_op, because
> > that requires a non-const lvalue.
> >
> > It should work if you change your first lambda to:
> >
> > [](Obj a,Obj const &b) { a.combine(b); return a; }
>
> Thanks for your quick response. Sure, taking that arg by value works.
> But my initial intention was to avoid copying of objects (they might
> become large) as much as possible, thus passing by reference or moving.
>

Returning by value is not expensive in C++17. The values will be moved
whenever possible, or the copy will be elided completely.

As I wrote, the statement compiles (and works) when policy is
> execution::seq - which strikes me as odd...
>

Failing to meet the function's requirements doesn't mean it definitely
won't compile.

>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: transform-reduce compiling with seq but not par - bug?
  2020-12-19 10:32     ` Jonathan Wakely
@ 2020-12-19 21:40       ` Kai
  0 siblings, 0 replies; 5+ messages in thread
From: Kai @ 2020-12-19 21:40 UTC (permalink / raw)
  To: gcc-help

On 19/12/2020 11:32, Jonathan Wakely wrote:
> On Fri, 18 Dec 2020, 23:42 Kai via Gcc-help, <gcc-help@gcc.gnu.org
> <mailto:gcc-help@gcc.gnu.org>> wrote:
>     But my initial intention was to avoid copying of objects (they might
>     become large) as much as possible, thus passing by reference or
moving.
>
> Returning by value is not expensive in C++17. The values will be moved
> whenever possible, or the copy will be elided completely.
>
>     As I wrote, the statement compiles (and works) when policy is
>     execution::seq - which strikes me as odd...
>
> Failing to meet the function's requirements doesn't mean it definitely
> won't compile.

Thanks again, also for your additional explanation and the (unexpected
:) ) bug report.

Cheers, Kai

--
"25 years from now will you come to my cremation?"      <The Beautiful
South>
D-55120 Meenz
++ PGP Key fingerprint  059D 4FAA FE93 5928 1B22  7FAF EC08 5BF9 D50E
F933 ++
-----BEGIN GEEK CODE BLOCK-----
VERSION: 3.12
GCS/IT d- s: a++>-----(?) C++$ UL++(++++$) P++ L++$ E-(+) W--(+) N !w---
!O !M V? PS+ PE-() Y+ PGP++ t R@* tv--(-) b+>++ DI++ G e+++(*) h? y?
------END GEEK CODE BLOCK------

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-12-19 21:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-18 22:33 transform-reduce compiling with seq but not par - bug? Kai
2020-12-18 22:49 ` Jonathan Wakely
2020-12-18 23:41   ` Kai
2020-12-19 10:32     ` Jonathan Wakely
2020-12-19 21:40       ` Kai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).