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

Add GCC9 to CI and reengineer Tuple #433

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ jobs:
fail-fast: false
matrix:
include:
- name: build-ubuntu-gcc9
env: {CXX: g++-9}
#- name: build-ubuntu-gcc9-cuda11.0
# env: {CXX: g++-9, CUDA_URL: "https://developer.download.nvidia.com/compute/cuda/11.0.3/local_installers/cuda_11.0.3_450.51.06_linux.run"}
# cuda: true
Expand Down
207 changes: 126 additions & 81 deletions include/llama/Tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,112 @@

namespace llama
{
// for implementation ideas, see e.g.:
// http://mitchnull.blogspot.com/2012/06/c11-tuple-implementation-details-part-1.html

template<typename... Elements>
struct Tuple
struct Tuple;

namespace internal
{
};
template<std::size_t I, typename T, bool = std::is_empty_v<T> && !std::is_final_v<T>>
struct TupleImplLeaf
{
T val;

LLAMA_FN_HOST_ACC_INLINE constexpr auto value() -> T&
{
return val;
}

LLAMA_FN_HOST_ACC_INLINE constexpr auto value() const -> const T&
{
return val;
}
};

template<std::size_t I, typename T>
struct TupleImplLeaf<I, T, true> : T
{
LLAMA_FN_HOST_ACC_INLINE constexpr auto value() -> T&
{
return *this;
}

LLAMA_FN_HOST_ACC_INLINE constexpr auto value() const -> const T&
{
return *this;
}
};

template<typename... IsAndElements>
struct TupleImpl;

template<>
struct TupleImpl<std::index_sequence<>>
{
};

template<std::size_t... Is, typename... Elements>
struct TupleImpl<std::index_sequence<Is...>, Elements...> : TupleImplLeaf<Is, Elements>...
{
using FirstElement = boost::mp11::mp_first<Tuple<Elements...>>;
using RestTuple = boost::mp11::mp_pop_front<Tuple<Elements...>>;

constexpr TupleImpl() = default;

/// Construct a tuple from values of the same types as the tuple stores.
LLAMA_FN_HOST_ACC_INLINE constexpr explicit TupleImpl(Elements... args)
: TupleImplLeaf<Is, Elements>{args}...
{
}

/// Construct a tuple from forwarded values of potentially different types as the tuple stores.
template<
typename... Ts,
std::enable_if_t<
sizeof...(Elements) == sizeof...(Ts) && (std::is_constructible_v<Elements, Ts> && ...),
int> = 0>
LLAMA_FN_HOST_ACC_INLINE constexpr explicit TupleImpl(Ts&&... args)
: TupleImplLeaf<Is, Elements>{Elements(std::move(args))}...
{
}
};
} // namespace internal

/// Tuple class like `std::tuple` but suitable for use with offloading devices like GPUs.
template<typename TFirstElement, typename... Elements>
struct Tuple<TFirstElement, Elements...>
/// Tuple class like `std::tuple` but suitable for use with offloading devices like GPUs. See also \ref
/// internal::TupleImpl.
template<typename... Elements>
struct Tuple : internal::TupleImpl<std::index_sequence_for<Elements...>, Elements...>
{
using FirstElement = TFirstElement;
using RestTuple = Tuple<Elements...>;
private:
template<std::size_t I>
using Base = internal::TupleImplLeaf<I, boost::mp11::mp_at_c<boost::mp11::mp_list<Elements...>, I>>;

constexpr Tuple() = default;
public:
using internal::TupleImpl<std::index_sequence_for<Elements...>, Elements...>::TupleImpl;

/// Construct a tuple from values of the same types as the tuple stores.
LLAMA_FN_HOST_ACC_INLINE constexpr explicit Tuple(FirstElement first, Elements... rest)
: first(std::move(first))
, rest(std::move(rest)...)
template<std::size_t Pos>
LLAMA_FN_HOST_ACC_INLINE friend constexpr auto get(Tuple& tuple) -> auto&
{
return tuple.Base<Pos>::value();
}

/// Construct a tuple from forwarded values of potentially different types as the tuple stores.
// SFINAE away this ctor if tuple elements cannot be constructed from ctor arguments
template<
typename T,
typename... Ts,
std::enable_if_t<
sizeof...(Elements) == sizeof...(Ts)
&& std::is_constructible_v<TFirstElement, T> && (std::is_constructible_v<Elements, Ts> && ...),
int> = 0>
LLAMA_FN_HOST_ACC_INLINE constexpr explicit Tuple(T&& firstArg, Ts&&... restArgs)
: first(std::forward<T>(firstArg))
, rest(std::forward<Ts>(restArgs)...)
template<std::size_t Pos>
LLAMA_FN_HOST_ACC_INLINE friend constexpr auto get(const Tuple& tuple) -> const auto&
{
return tuple.Base<Pos>::value();
}

FirstElement first; ///< the first element (if existing)
#ifndef __NVCC__
[[no_unique_address]] // nvcc 11.3 ICE
#endif
RestTuple rest; ///< the remaining elements
};

template<typename... Elements>
Tuple(Elements...) -> Tuple<std::remove_cv_t<std::remove_reference_t<Elements>>...>;

template<std::size_t Pos, typename... Elements>
LLAMA_FN_HOST_ACC_INLINE constexpr auto get(Tuple<Elements...>& tuple) -> auto&
{
if constexpr(Pos == 0)
return tuple.first;
else
return get<Pos - 1>(tuple.rest);
}
constexpr auto get(Tuple<Elements...>& tuple);

template<std::size_t Pos, typename... Elements>
LLAMA_FN_HOST_ACC_INLINE constexpr auto get(const Tuple<Elements...>& tuple) -> const auto&
{
if constexpr(Pos == 0)
return tuple.first;
else
return get<Pos - 1>(tuple.rest);
}
constexpr auto get(const Tuple<Elements...>& tuple);

template<typename... Elements>
Tuple(Elements...) -> Tuple<std::remove_cv_t<std::remove_reference_t<Elements>>...>;
} // namespace llama

template<typename... Elements>
Expand Down Expand Up @@ -143,44 +186,34 @@ namespace llama

namespace internal
{
template<std::size_t Pos, typename Tuple, typename Replacement>
struct TupleReplaceImpl
{
LLAMA_FN_HOST_ACC_INLINE
auto operator()(Tuple const tuple, Replacement const replacement)
{
return tupleCat(
llama::Tuple{tuple.first},
TupleReplaceImpl<Pos - 1, typename Tuple::RestTuple, Replacement>()(tuple.rest, replacement));
};
};

template<typename... Elements, typename Replacement>
struct TupleReplaceImpl<0, Tuple<Elements...>, Replacement>
{
LLAMA_FN_HOST_ACC_INLINE
auto operator()(Tuple<Elements...> tuple, Replacement const replacement)
{
return tupleCat(Tuple{replacement}, tuple.rest);
};
};

template<typename OneElement, typename Replacement>
struct TupleReplaceImpl<0, Tuple<OneElement>, Replacement>
template<
std::size_t Pos,
typename Tuple,
typename Replacement,
std::size_t... IsBefore,
std::size_t... IsAfter>
LLAMA_FN_HOST_ACC_INLINE constexpr auto tupleReplaceImpl(
Tuple&& tuple,
Replacement&& replacement,
std::index_sequence<IsBefore...>,
std::index_sequence<IsAfter...>)
{
LLAMA_FN_HOST_ACC_INLINE
auto operator()(Tuple<OneElement>, Replacement const replacement)
{
return Tuple{replacement};
}
};
return llama::Tuple{
get<IsBefore>(std::forward<Tuple>(tuple))...,
std::forward<Replacement>(replacement),
get<Pos + 1 + IsAfter>(std::forward<Tuple>(tuple))...};
}
} // namespace internal

/// Creates a copy of a tuple with the element at position Pos replaced by replacement.
template<std::size_t Pos, typename Tuple, typename Replacement>
LLAMA_FN_HOST_ACC_INLINE auto tupleReplace(Tuple tuple, Replacement replacement)
LLAMA_FN_HOST_ACC_INLINE constexpr auto tupleReplace(Tuple&& tuple, Replacement&& replacement)
{
return internal::TupleReplaceImpl<Pos, Tuple, Replacement>()(tuple, replacement);
return internal::tupleReplaceImpl<Pos>(
std::forward<Tuple>(tuple),
std::forward<Replacement>(replacement),
std::make_index_sequence<Pos>{},
std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>> - Pos - 1>{});
}

namespace internal
Expand All @@ -206,10 +239,22 @@ namespace llama
return internal::tupleTransformHelper(std::make_index_sequence<sizeof...(Elements)>{}, tuple, functor);
}

namespace internal
{
template<std::size_t Count = 1, typename... Elements, size_t... Is>
LLAMA_FN_HOST_ACC_INLINE constexpr auto pop_front_impl(
const Tuple<Elements...>& tuple,
std::index_sequence<Is...>)
{
return Tuple{get<Count + Is>(tuple)...};
}
} // namespace internal

/// Returns a copy of the tuple without the first element.
template<typename... Elements>
template<std::size_t Count = 1, typename... Elements>
LLAMA_FN_HOST_ACC_INLINE constexpr auto pop_front(const Tuple<Elements...>& tuple)
{
return tuple.rest;
static_assert(sizeof...(Elements) > 0);
return internal::pop_front_impl<Count>(tuple, std::make_index_sequence<sizeof...(Elements) - Count>{});
}
} // namespace llama
2 changes: 1 addition & 1 deletion include/llama/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace llama
using RecordDim = typename View::RecordDim;
forEachADCoord(
view.mapping().extents(),
[&](typename View::ArrayIndex ai)
[&]([[maybe_unused]] typename View::ArrayIndex ai)
{
if constexpr(isRecord<RecordDim> || internal::IsBoundedArray<RecordDim>::value)
forEachLeafCoord<RecordDim>(
Expand Down
44 changes: 25 additions & 19 deletions include/llama/mapping/tree/Functors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,20 @@ namespace llama::mapping::tree::functor
const NodeOrLeaf& nodeOrLeaf,
std::size_t arraySize = 0)
{
constexpr auto ci = BasicCoord::FirstElement::childIndex;
if constexpr(std::tuple_size_v<BasicCoord> == 1)
return Tuple{TreeCoordElement<BasicCoord::FirstElement::childIndex>{
arraySize + LLAMA_COPY(basicCoord.first.arrayIndex)}};
return Tuple{TreeCoordElement<ci>{arraySize + LLAMA_COPY(get<0>(basicCoord).arrayIndex)}};
else
{
const auto& branch = get<BasicCoord::FirstElement::childIndex>(nodeOrLeaf.childs);
auto first = TreeCoordElement<BasicCoord::FirstElement::childIndex, boost::mp11::mp_size_t<0>>{};
const auto& branch = get<ci>(nodeOrLeaf.childs);
auto first = TreeCoordElement<ci, boost::mp11::mp_size_t<0>>{};

return tupleCat(
Tuple{first},
basicCoordToResultCoordImpl(
basicCoord.rest,
pop_front(basicCoord),
branch,
(arraySize + LLAMA_COPY(basicCoord.first.arrayIndex)) * LLAMA_COPY(branch.count)));
(arraySize + LLAMA_COPY(get<0>(basicCoord).arrayIndex)) * LLAMA_COPY(branch.count)));
}
}
};
Expand All @@ -105,7 +105,10 @@ namespace llama::mapping::tree::functor
if constexpr(std::is_same_v<TreeCoord, Tuple<>>)
return node;
else
return getNode<typename TreeCoord::RestTuple>(get<TreeCoord::FirstElement::childIndex>(node.childs));
{
constexpr auto ci = TreeCoord::FirstElement::childIndex;
return getNode<typename TreeCoord::RestTuple>(get<ci>(node.childs));
}
}

template<typename TreeCoord, typename Identifier, typename Type, typename CountType>
Expand All @@ -117,9 +120,10 @@ namespace llama::mapping::tree::functor
return Node<Identifier, Type>{newValue, tree.childs};
else
{
auto current = get<TreeCoord::FirstElement::childIndex>(tree.childs);
constexpr auto ci = TreeCoord::FirstElement::childIndex;
auto current = get<ci>(tree.childs);
auto replacement = changeNodeRuntime<typename TreeCoord::RestTuple>(current, newValue);
auto children = tupleReplace<TreeCoord::FirstElement::childIndex>(tree.childs, replacement);
auto children = tupleReplace<ci>(tree.childs, replacement);
return Node<Identifier, decltype(children)>{tree.count, children};
}
}
Expand Down Expand Up @@ -161,9 +165,10 @@ namespace llama::mapping::tree::functor
}
else
{
auto current = get<TreeCoord::FirstElement::childIndex>(tree.childs);
constexpr auto ci = TreeCoord::FirstElement::childIndex;
auto current = get<ci>(tree.childs);
auto replacement = changeNodeChildsRuntime<typename TreeCoord::RestTuple>(current, newValue);
auto children = tupleReplace<TreeCoord::FirstElement::childIndex>(tree.childs, replacement);
auto children = tupleReplace<ci>(tree.childs, replacement);
return Node<Identifier, decltype(children)>{tree.count, children};
}
}
Expand Down Expand Up @@ -214,31 +219,32 @@ namespace llama::mapping::tree::functor
template<typename InternalTreeCoord, typename BasicCoord, typename Tree>
LLAMA_FN_HOST_ACC_INLINE auto basicCoordToResultCoordImpl(const BasicCoord& basicCoord, const Tree& tree) const
{
constexpr auto ci = BasicCoord::FirstElement::childIndex;
if constexpr(std::is_same_v<InternalTreeCoord, Tuple<>>)
{
if constexpr(std::is_same_v<BasicCoord, Tuple<>>)
return Tuple{};
else
{
const auto& childTree = get<BasicCoord::FirstElement::childIndex>(tree.childs);
const auto rt1 = basicCoord.first.arrayIndex / amount;
const auto& childTree = get<ci>(tree.childs);
const auto rt1 = get<0>(basicCoord).arrayIndex / amount;
const auto rt2
= basicCoord.first.arrayIndex % amount * childTree.count + basicCoord.rest.first.arrayIndex;
auto rt1Child = TreeCoordElement<BasicCoord::FirstElement::childIndex>{rt1};
= get<0>(basicCoord).arrayIndex % amount * childTree.count + get<1>(basicCoord).arrayIndex;
auto rt1Child = TreeCoordElement<ci>{rt1};
auto rt2Child = TreeCoordElement<BasicCoord::RestTuple::FirstElement::childIndex>{rt2};
return tupleCat(Tuple{rt1Child}, tupleCat(Tuple{rt2Child}, pop_front(basicCoord.rest)));
return tupleCat(Tuple{rt1Child}, tupleCat(Tuple{rt2Child}, pop_front<2>(basicCoord)));
}
}
else
{
if constexpr(InternalTreeCoord::FirstElement::childIndex != BasicCoord::FirstElement::childIndex)
if constexpr(InternalTreeCoord::FirstElement::childIndex != ci)
return basicCoord;
else
{
auto rest = basicCoordToResultCoordImpl<typename InternalTreeCoord::RestTuple>(
pop_front(basicCoord),
get<BasicCoord::FirstElement::childIndex>(tree.childs));
return tupleCat(Tuple{basicCoord.first}, rest);
get<ci>(tree.childs));
return tupleCat(Tuple{get<0>(basicCoord)}, rest);
}
}
}
Expand Down
Loading