Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

datapar algorithm instantiated with wrong type #2402

Closed
DavidPfander-UniStuttgart opened this issue Nov 21, 2016 · 5 comments

Comments

Projects
None yet
3 participants
@DavidPfander-UniStuttgart
Copy link
Contributor

commented Nov 21, 2016

Hi,

I'm trying to compile a simple datapar example with HPX and Vc. The lambda should be compiled in two versions: One with the Vc vector-type and one with the Vc scalar-type. But the error I get from my compiler indicates that it is also compiled with 'double &' as its type.

#include <hpx/include/parallel_for_each.hpp>

#include <boost/range/functions.hpp>

int main(int argc, char **argv) {
  std::vector<double> large(64);
  
  auto zip_it_begin = hpx::util::make_zip_iterator(boost::begin(large));
  auto zip_it_end = hpx::util::make_zip_iterator(boost::end(large));
  
  hpx::parallel::for_each(hpx::parallel::datapar_execution, zip_it_begin, zip_it_end, [](auto t) {
      using comp_type = typename hpx::util::tuple_element<0, decltype(t)>::type;
      using var_type = typename hpx::util::decay<comp_type>::type;

      var_type mass_density = 0.0;
      mass_density(mass_density > 0.0) = 7.0;
    });
  return 0;
}

Compiler message, note the second line:

g++-6 -o debug/wrong_type.o -c -std=c++14 -fopenmp -Wall -Wno-ignored-attributes -Wno-unused-local-typedefs -O0 -g -fno-omit-frame-pointer -DHPX_DEBUG -DHPX_APPLICATION_EXPORTS -DHPX_ENABLE_ASSERT_HANDLER -Ihpx_install_debug/include -Ihpx_install_debug/include/hpx/external -IVc_install_debug/include -Iboost_1_62_0_install_debug/include wrong_type.cpp
wrong_type.cpp: In instantiation of ‘main(int, char**)::<lambda(auto:1)> [with auto:1 = hpx::util::tuple<double&>]’:
hpx_install_debug/include/hpx/util/result_of.hpp:43:39:   required by substitution of ‘template<class F, class ... Ts> decltype (declval<F>()((declval<Ts>)()...)) hpx::util::detail::result_of_function_object_impl::invoke(F&&, Ts&& ...) [with F = main(int, char**)::<lambda(auto:1)>; Ts = {hpx::util::tuple<double&>}]’
hpx_install_debug/include/hpx/util/result_of.hpp:52:72:   required from ‘struct hpx::util::detail::result_of_function_object_impl::result_of_invoke<main(int, char**)::<lambda(auto:1)>(hpx::util::tuple<double&>&&)>’
hpx_install_debug/include/hpx/util/result_of.hpp:151:16:   required from ‘struct hpx::util::detail::result_of_impl<main(int, char**)::<lambda(auto:1)>, main(int, char**)::<lambda(auto:1)>(hpx::util::tuple<double&>&&)>’
hpx_install_debug/include/hpx/util/result_of.hpp:182:12:   required from ‘struct hpx::util::result_of<main(int, char**)::<lambda(auto:1)>(hpx::util::tuple<double&>&&)>’
hpx_install_debug/include/hpx/traits/is_callable.hpp:47:12:   required from ‘struct hpx::traits::is_callable<main(int, char**)::<lambda(auto:1)>(hpx::util::tuple<double&>&&), void>’
hpx_install_debug/include/hpx/parallel/traits/projected.hpp:138:16:   required from ‘struct hpx::parallel::traits::detail::is_indirect_callable_impl<main(int, char**)::<lambda(auto:1)>, hpx::util::tuple<double&>&&>’
hpx_install_debug/include/hpx/parallel/traits/projected.hpp:148:16:   required from ‘struct hpx::parallel::traits::detail::is_indirect_callable<main(int, char**)::<lambda(auto:1)>, hpx::util::detail::pack<hpx::parallel::traits::projected<hpx::parallel::util::projection_identity, hpx::util::zip_iterator<__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > > > > >, void>’
hpx_install_debug/include/hpx/parallel/traits/projected.hpp:160:12:   required from ‘struct hpx::parallel::traits::is_indirect_callable<main(int, char**)::<lambda(auto:1)>, hpx::parallel::traits::projected<hpx::parallel::util::projection_identity, hpx::util::zip_iterator<__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > > > > >’
hpx_install_debug/include/hpx/parallel/algorithms/for_each.hpp:408:5:   required by substitution of ‘template<class ExPolicy, class InIter, class F, class Proj, int _concept_requires_414, typename std::enable_if<((_concept_requires_414 == 43) || (((hpx::parallel::v1::is_execution_policy<T>::value && hpx::traits::is_iterator<Iter>::value) && hpx::parallel::traits::is_projected<Proj, InIter>::value) && hpx::parallel::traits::is_indirect_callable<F, hpx::parallel::traits::projected<Proj, InIter> >::value)), int>::type _concept_check_414> typename hpx::parallel::util::detail::algorithm_result<ExPolicy, T>::type hpx::parallel::v1::for_each(ExPolicy&&, InIter, InIter, F&&, Proj&&) [with ExPolicy = const hpx::parallel::v1::datapar_execution_policy&; InIter = hpx::util::zip_iterator<__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > > >; F = main(int, char**)::<lambda(auto:1)>; Proj = hpx::parallel::util::projection_identity; int _concept_requires_414 = 42; typename std::enable_if<((_concept_requires_414 == 43) || (((hpx::parallel::v1::is_execution_policy<T>::value && hpx::traits::is_iterator<Iter>::value) && hpx::parallel::traits::is_projected<Proj, InIter>::value) && hpx::parallel::traits::is_indirect_callable<F, hpx::parallel::traits::projected<Proj, InIter> >::value)), int>::type _concept_check_414 = <missing>]’
wrong_type.cpp:18:6:   required from here
wrong_type.cpp:17:19: error: ‘mass_density’ cannot be used as a function
       mass_density(mass_density > 0.0) = 7.0;
       ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
@K-ballo

This comment has been minimized.

Copy link
Member

commented Nov 21, 2016

The definition of your lambda is incomplete, and merely looking at the declaration will implicitly instantiate the body. Would you try doing [](auto t) -> void { ... } instead? Sorry...

@DavidPfander-UniStuttgart

This comment has been minimized.

Copy link
Contributor Author

commented Nov 21, 2016

Hi, thanks for your reply. It does build successfully with the return type specified. But why? I thought that not having a return statement meant that the implicit return type would be void.

@K-ballo

This comment has been minimized.

Copy link
Member

commented Nov 21, 2016

A lambda with no explicit return type does implicit return type deduction, and the rules governing implicit return type deduction are ... let's say suboptimal.

Don't close this issue just yet. It might be possible to do policy dispatch in two steps in such a way that code like this one is valid, or at least so that there's less superfluous lambda instantiation taking place.

@hkaiser

This comment has been minimized.

Copy link
Member

commented Nov 21, 2016

@K-ballo What do you have in mind?

@hkaiser

This comment has been minimized.

Copy link
Member

commented Nov 22, 2016

For future reference: the problem is caused by the concept checking associated with the function hpx::parallel::for_each. There we try to make sure that the provided function object is compatible with the value_type of the used iterators (after projection). However, when using the datapar execution policy, the function object is not invoked using the projected value_type but using a SIMD vector-pack instance which is constructed on the fly.

The concept checking code currently instantiates the provided function object (lambda) using the projected value_type of the used iterator which leads to the compilation problems noted above.

I see two possible solutions:

  • overload the for_each algorithm (and all others) for the datapar execution policy and adapt the concept checking code for those (see @K-ballo double-dispatch suggestion above)
  • change the parallel::traits::is_indirect_callable concept check to additionalloy take the execution policy and specialize this for the datapar execution policies (and friends)

hkaiser added a commit that referenced this issue Nov 25, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.