[llvm-bugs] [Bug 47602] New: __internal::__lazy_and needs to be more lazy

via llvm-bugs llvm-bugs at lists.llvm.org
Mon Sep 21 09:17:05 PDT 2020


https://bugs.llvm.org/show_bug.cgi?id=47602

            Bug ID: 47602
           Summary: __internal::__lazy_and needs to be more lazy
           Product: parallel STL
           Version: unspecified
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: New
          Assignee: ldionne at apple.com
          Reporter: zilla at kayari.org
                CC: llvm-bugs at lists.llvm.org

In pstl/include/pstl/internal/execution_impl.h these function templates are
defined:

template <typename _Tp>
std::false_type __lazy_and(_Tp, std::false_type)
{
    return std::false_type{};
};

template <typename _Tp>
inline _Tp
__lazy_and(_Tp __a, std::true_type)
{
    return __a;
}

(There are also __lazy_or function template which seem to be completely
unused).

It gets used in code like this:

template <typename _ExecutionPolicy, typename... _IteratorTypes>
auto
__is_vectorization_preferred(_ExecutionPolicy&& __exec)
    -> decltype(__internal::__lazy_and(__exec.__allow_vector(),
                                       typename
__internal::__is_random_access_iterator<_IteratorTypes...>::type()))
{
    return __internal::__lazy_and(__exec.__allow_vector(),
                                  typename
__internal::__is_random_access_iterator<_IteratorTypes...>::type());
}


Where __allow_vector is a specialization of a relatively inexpensive class
template, and __is_random_access_iterator is a recursive class template:


template <typename _IteratorType, typename... _OtherIteratorTypes>
struct __is_random_access_iterator
{
    static constexpr bool value =
__internal::__is_random_access_iterator<_IteratorType>::value &&
                                 
__internal::__is_random_access_iterator<_OtherIteratorTypes...>::value;
    typedef std::integral_constant<bool, value> type;
};

template <typename _IteratorType>
struct __is_random_access_iterator<_IteratorType>
    : std::is_same<typename
std::iterator_traits<_IteratorType>::iterator_category,
std::random_access_iterator_tag>
{
};


Unless I'm mistaken, the only thing that is lazy here is the instantiation of
__allow_vector::value, which is cheap anyway.

In order to choose an overload of __lazy_and the second argument needs to be
complete, which instantiates
__is_random_access_iterator<_IteratorTypes...>::type which requires the
instantiation of __is_random_access_iterator<_IteratorTypes...>::value, which
is VERY UN-LAZY. It requires instantiating __is_random_access_iterator for
every element of the pack, even if the first element is not a random access
iterator.

A better implementation of __is_random_access_iterator would be:

template <typename _IteratorType, typename... _OtherIteratorTypes>
struct __is_random_access_iterator;

template <typename _IteratorType>
struct __is_random_access_iterator<_IteratorType>
    : std::is_same<typename
std::iterator_traits<_IteratorType>::iterator_category,
std::random_access_iterator_tag>
{
};

template <typename _IteratorType, typename... _OtherIteratorTypes>
struct __is_random_access_iterator
    : std::conjunction<__is_random_access_iterator<_IteratorType>,
                      
__is_random_access_iterator<_OtherIteratorTypes>...>::type
{
};

Personally I'd get rid of __lazy_and completely, make
__is_random_access_iterator non-variadic, and write the functions using it like
this (assuming bug 47601 gets fixed so the __alow_vector alias template works):

template <typename _ExecutionPolicy, typename... _IteratorTypes>
typename std::conjunction<__allow_vector<_ExecutionPolicy>,
           __is_random_access_iterator<_IteratorTypes>...>::type
__is_vectorization_preferred(_ExecutionPolicy&&)
{
    return {};
}


This is actually lazy. It never instantiates any __is_random_access_iterator
specialization if the __allow_vector trait is false, and only instantiates as
many as needed to determine the answer.

(N.B. the __exec parameter is redundant, since the _ExecutionPolicy type has to
be given explicitly anyway, and that already provides all the information
required, but changing that would require changes to every caller).

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200921/a0a07462/attachment.html>


More information about the llvm-bugs mailing list