From 60c4dca6dd9e7e905fe89ee8e11dd7a208f84060 Mon Sep 17 00:00:00 2001 From: Bernhard Manfred Gruber Date: Sun, 7 Mar 2021 17:44:36 +0100 Subject: [PATCH] support sub arrays of dynamic size as field type * allow dynamic field types in the record dimension * add specializations to most of the core functions * add llama::dynamic to signal a dynamic array member in a RecordCoord * extend VirtualRecord to allow holding dynamic indices * extend blobNrAndOffset to allow for additional dynamic indices * add OffsetTable mapping * add customization allowing to dump OffsetTable mappings * add a few unit tests --- examples/bufferguard/bufferguard.cpp | 4 +- include/llama/Core.hpp | 53 ++++ include/llama/DumpMapping.hpp | 20 ++ include/llama/RecordCoord.hpp | 3 + include/llama/View.hpp | 29 +- include/llama/VirtualRecord.hpp | 95 ++++++- include/llama/llama.hpp | 1 + include/llama/mapping/AoS.hpp | 6 +- include/llama/mapping/AoSoA.hpp | 6 +- include/llama/mapping/Heatmap.hpp | 4 +- include/llama/mapping/OffsetTable.hpp | 354 +++++++++++++++++++++++++ include/llama/mapping/One.hpp | 5 +- include/llama/mapping/SoA.hpp | 6 +- include/llama/mapping/Split.hpp | 19 +- include/llama/mapping/Trace.hpp | 5 +- include/llama/mapping/tree/Mapping.hpp | 5 +- tests/computedprop.cpp | 15 +- tests/core.cpp | 30 ++- tests/recorddimension.cpp | 214 +++++++++++++++ 19 files changed, 822 insertions(+), 52 deletions(-) create mode 100644 include/llama/mapping/OffsetTable.hpp diff --git a/examples/bufferguard/bufferguard.cpp b/examples/bufferguard/bufferguard.cpp index ebc10971ef..d80ff7172e 100644 --- a/examples/bufferguard/bufferguard.cpp +++ b/examples/bufferguard/bufferguard.cpp @@ -69,8 +69,8 @@ struct GuardMapping2D std::abort(); } - template - constexpr auto blobNrAndOffset(ArrayDims coord) const -> llama::NrAndOffset + template + constexpr auto blobNrAndOffset(ArrayDims coord, llama::Array = {}) const -> llama::NrAndOffset { // [0][0] is at left top const auto [row, col] = coord; diff --git a/include/llama/Core.hpp b/include/llama/Core.hpp index f7f14c0ff3..1fa5d0ecc9 100644 --- a/include/llama/Core.hpp +++ b/include/llama/Core.hpp @@ -58,6 +58,15 @@ namespace llama inline constexpr bool isAllowedFieldType = std::is_trivially_constructible_v&& std::is_trivially_destructible_v; + template + inline constexpr bool isAllowedFieldType> = true; + + template + inline constexpr bool isAllowedFieldType = isAllowedFieldType; + + template + inline constexpr bool isAllowedFieldType = isAllowedFieldType; + /// Record dimension tree node which may either be a leaf or refer to a child tree presented as another \ref /// Record. /// \tparam Tag Name of the node. May be any type (struct, class). @@ -134,6 +143,14 @@ namespace llama mp_push_front>::type, CurrTag>; }; + template + struct GetTagsImpl> + { + using ChildTag = RecordCoord; + using type = boost::mp11:: + mp_push_front>::type, CurrTag>; + }; + template struct GetTagsImpl> { @@ -212,6 +229,16 @@ namespace llama typename GetCoordFromTagsImpl, Tags...>::type; }; + template + struct GetCoordFromTagsImpl, FirstTag, Tags...> + { + static_assert( + std::is_same_v>, + "Please use a RecordCoord to index into dynamic arrays"); + using type = + typename GetCoordFromTagsImpl, Tags...>::type; + }; + template struct GetCoordFromTagsImpl { @@ -244,6 +271,13 @@ namespace llama using type = typename GetTypeImpl>::type; }; + template + struct GetTypeImpl> + { + static_assert(HeadCoord == dynamic, "Record coord at a dynamic array must be llama::dynamic"); + using type = typename GetTypeImpl>::type; + }; + template struct GetTypeImpl> { @@ -309,6 +343,12 @@ namespace llama } using type = decltype(help(std::make_index_sequence{})); }; + + template + struct LeafRecordCoordsImpl> + { + using type = typename LeafRecordCoordsImpl>::type; + }; } // namespace internal /// Returns a flat type list containing all record coordinates to all leaves of the given record dimension. @@ -553,5 +593,18 @@ namespace llama struct is_bounded_array : std::true_type { }; + + template + struct is_unbounded_array : std::false_type + { + }; + + template + struct is_unbounded_array : std::true_type + { + }; + + template + inline constexpr bool is_unbounded_array_v = is_unbounded_array::value; } // namespace internal } // namespace llama diff --git a/include/llama/DumpMapping.hpp b/include/llama/DumpMapping.hpp index a4b3561481..e430405918 100644 --- a/include/llama/DumpMapping.hpp +++ b/include/llama/DumpMapping.hpp @@ -4,6 +4,7 @@ #include "ArrayDimsIndexRange.hpp" #include "Core.hpp" +#include "mapping/OffsetTable.hpp" #include #include @@ -138,6 +139,25 @@ namespace llama return infos; } + template + auto boxesFromMapping(const mapping::OffsetTable& mapping) + -> std::vector> + { + std::size_t previousBlobs = 0; + std::vector> infos; + boost::mp11::mp_for_each>>( + [&](auto ic) + { + const auto& subMapping = get(mapping.subMappings); + auto subBoxes = boxesFromMapping(subMapping); + for (auto& box : subBoxes) + box.nrAndOffset.nr += previousBlobs; + infos.insert(infos.end(), subBoxes.begin(), subBoxes.end()); + previousBlobs += std::decay_t::blobCount; + }); + return infos; + } + template auto breakBoxes(std::vector> boxes, std::size_t wrapByteCount) -> std::vector> { diff --git a/include/llama/RecordCoord.hpp b/include/llama/RecordCoord.hpp index 635b7a7aee..b4a7cd0511 100644 --- a/include/llama/RecordCoord.hpp +++ b/include/llama/RecordCoord.hpp @@ -5,10 +5,13 @@ #include #include +#include #include namespace llama { + inline constexpr auto dynamic = std::numeric_limits::max(); + /// Represents a coordinate for a record inside the record dimension tree. /// \tparam Coords... the compile time coordinate. template diff --git a/include/llama/View.hpp b/include/llama/View.hpp index 1f2213dc49..ac145c917f 100644 --- a/include/llama/View.hpp +++ b/include/llama/View.hpp @@ -265,12 +265,12 @@ namespace llama if constexpr (isRecord || internal::is_bounded_array::value) { LLAMA_FORCE_INLINE_RECURSIVE - return VirtualRecordTypeConst{arrayDims, *this}; + return VirtualRecordTypeConst{*this, arrayDims}; } else { LLAMA_FORCE_INLINE_RECURSIVE - return accessor(arrayDims, RecordCoord<>{}); + return accessor(arrayDims, Array{}, RecordCoord<>{}); } } @@ -279,12 +279,12 @@ namespace llama if constexpr (isRecord || internal::is_bounded_array::value) { LLAMA_FORCE_INLINE_RECURSIVE - return VirtualRecordType{arrayDims, *this}; + return VirtualRecordType{*this, arrayDims}; } else { LLAMA_FORCE_INLINE_RECURSIVE - return accessor(arrayDims, RecordCoord<>{}); + return accessor(arrayDims, Array{}, RecordCoord<>{}); } } @@ -375,29 +375,34 @@ namespace llama friend struct VirtualRecord; LLAMA_SUPPRESS_HOST_DEVICE_WARNING - template - LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayDims arrayDims, RecordCoord dc = {}) const - -> decltype(auto) + template + LLAMA_FN_HOST_ACC_INLINE auto accessor( + ArrayDims arrayDims, + Array dynamicArrayExtents, + RecordCoord dc = {}) const -> decltype(auto) { if constexpr (isComputed>) return mapping.compute(arrayDims, dc, storageBlobs); else { - const auto [nr, offset] = mapping.template blobNrAndOffset(arrayDims); + const auto [nr, offset] = mapping.template blobNrAndOffset(arrayDims, dynamicArrayExtents); using Type = GetType>; return reinterpret_cast(storageBlobs[nr][offset]); } } LLAMA_SUPPRESS_HOST_DEVICE_WARNING - template - LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayDims arrayDims, RecordCoord dc = {}) -> decltype(auto) + template + LLAMA_FN_HOST_ACC_INLINE auto accessor( + ArrayDims arrayDims, + Array dynamicArrayExtents, + RecordCoord dc = {}) -> decltype(auto) { if constexpr (isComputed>) - return mapping.compute(arrayDims, dc, storageBlobs); + return mapping.compute(arrayDims, dynamicArrayExtents, dc, storageBlobs); else { - const auto [nr, offset] = mapping.template blobNrAndOffset(arrayDims); + const auto [nr, offset] = mapping.template blobNrAndOffset(arrayDims, dynamicArrayExtents); using Type = GetType>; return reinterpret_cast(storageBlobs[nr][offset]); } diff --git a/include/llama/VirtualRecord.hpp b/include/llama/VirtualRecord.hpp index 2cb030cea7..97698944af 100644 --- a/include/llama/VirtualRecord.hpp +++ b/include/llama/VirtualRecord.hpp @@ -309,6 +309,21 @@ namespace llama template typename Tuple, typename... Args> constexpr inline auto isDirectListInitializableFromTuple> = isDirectListInitializable; + + template + constexpr inline auto unboundArraysUntil = []() constexpr + { + std::size_t count = 0; + boost::mp11::mp_for_each>( + [&](auto i) constexpr + { + using RC = RecordCoordFromList>; + using TypeAtRC = GetType; + count += static_cast(internal::is_unbounded_array_v); + }); + return count; + } + (); } // namespace internal /// Virtual record type returned by \ref View after resolving an array dimensions coordinate or partially resolving @@ -324,9 +339,11 @@ namespace llama private: using ArrayDims = typename View::Mapping::ArrayDims; using RecordDim = typename View::Mapping::RecordDim; + using DynamicArrayExtentsArray = Array>; - [[no_unique_address]] const ArrayDims arrayDimsCoord; std::conditional_t view; + [[no_unique_address]] const ArrayDims arrayDimsCoord; + [[no_unique_address]] const DynamicArrayExtentsArray dynamicArrayExtents; public: /// Subtree of the record dimension of View starting at BoundRecordCoord. If BoundRecordCoord is `RecordCoord<>` @@ -337,15 +354,20 @@ namespace llama LLAMA_FN_HOST_ACC_INLINE VirtualRecord() /* requires(OwnView) */ : arrayDimsCoord({}) + , dynamicArrayExtents({}) , view{allocViewStack<0, RecordDim>()} { static_assert(OwnView, "The default constructor of VirtualRecord is only available if it owns the view."); } LLAMA_FN_HOST_ACC_INLINE - VirtualRecord(ArrayDims arrayDimsCoord, std::conditional_t view) - : arrayDimsCoord(arrayDimsCoord) - , view{static_cast(view)} + VirtualRecord( + std::conditional_t view, + ArrayDims arrayDimsCoord, + DynamicArrayExtentsArray dynamicArrayExtents = {}) + : view{static_cast(view)} + , arrayDimsCoord(arrayDimsCoord) + , dynamicArrayExtents{dynamicArrayExtents} { } @@ -388,15 +410,21 @@ namespace llama { using AbsolutCoord = Cat>; using AccessedType = GetType; - if constexpr (isRecord || internal::is_bounded_array::value) + if constexpr ( + isRecord || internal::is_bounded_array::value + || internal::is_unbounded_array_v) { LLAMA_FORCE_INLINE_RECURSIVE - return VirtualRecord{arrayDimsCoord, this->view}; + return VirtualRecord{ + this->view, + arrayDimsCoord, + dynamicArrayExtents, + }; } else { LLAMA_FORCE_INLINE_RECURSIVE - return this->view.accessor(arrayDimsCoord, AbsolutCoord{}); + return this->view.accessor(arrayDimsCoord, dynamicArrayExtents, AbsolutCoord{}); } } @@ -406,22 +434,24 @@ namespace llama { using AbsolutCoord = Cat>; using AccessedType = GetType; - if constexpr (isRecord || internal::is_bounded_array::value) + if constexpr ( + isRecord || internal::is_bounded_array::value + || internal::is_unbounded_array_v) { LLAMA_FORCE_INLINE_RECURSIVE - return VirtualRecord{arrayDimsCoord, this->view}; + return VirtualRecord{this->view, arrayDimsCoord, dynamicArrayExtents}; } else { LLAMA_FORCE_INLINE_RECURSIVE - return this->view.accessor(arrayDimsCoord, AbsolutCoord{}); + return this->view.accessor(arrayDimsCoord, dynamicArrayExtents, AbsolutCoord{}); } } /// Access a record in the record dimension underneath the current virtual record using a series of tags. If the /// access resolves to a leaf, a reference to a variable inside the \ref View storage is returned, otherwise /// another virtual record. - template + template ...>, bool> = true> LLAMA_FN_HOST_ACC_INLINE auto operator()(Tags...) const -> decltype(auto) { using RecordCoord = GetCoordFromTagsRelative; @@ -431,7 +461,7 @@ namespace llama } // FIXME(bgruber): remove redundancy - template + template ...>, bool> = true> LLAMA_FN_HOST_ACC_INLINE auto operator()(Tags...) -> decltype(auto) { using RecordCoord = GetCoordFromTagsRelative; @@ -440,6 +470,47 @@ namespace llama return operator()(RecordCoord{}); } + template < + typename ADD = AccessibleRecordDim, + std::enable_if_t, bool> = true> + LLAMA_FN_HOST_ACC_INLINE auto operator()(std::size_t i) const -> decltype(auto) + { + using AbsolutCoord = Cat>; + using ResolvedType = GetType; + auto newDynamicArrayExtents = push_back(dynamicArrayExtents, i); + if constexpr (isRecord || internal::is_unbounded_array_v) + { + LLAMA_FORCE_INLINE_RECURSIVE + return VirtualRecord{this->view, arrayDimsCoord, newDynamicArrayExtents}; + } + else + { + LLAMA_FORCE_INLINE_RECURSIVE + return this->view.accessor(arrayDimsCoord, newDynamicArrayExtents, AbsolutCoord{}); + } + } + + // FIXME(bgruber): remove redundancy + template < + typename ADD = AccessibleRecordDim, + std::enable_if_t, bool> = true> + LLAMA_FN_HOST_ACC_INLINE auto operator()(std::size_t i) -> decltype(auto) + { + using AbsolutCoord = Cat>; + using ResolvedType = GetType; + auto newDynamicArrayExtents = push_back(dynamicArrayExtents, i); + if constexpr (isRecord || internal::is_unbounded_array_v) + { + LLAMA_FORCE_INLINE_RECURSIVE + return VirtualRecord{this->view, arrayDimsCoord, newDynamicArrayExtents}; + } + else + { + LLAMA_FORCE_INLINE_RECURSIVE + return this->view.accessor(arrayDimsCoord, newDynamicArrayExtents, AbsolutCoord{}); + } + } + // we need this one to disable the compiler generated copy assignment LLAMA_FN_HOST_ACC_INLINE auto operator=(const VirtualRecord& other) -> VirtualRecord& { diff --git a/include/llama/llama.hpp b/include/llama/llama.hpp index 600122ff8c..7e7ea63630 100644 --- a/include/llama/llama.hpp +++ b/include/llama/llama.hpp @@ -43,6 +43,7 @@ #include "mapping/AoS.hpp" #include "mapping/AoSoA.hpp" #include "mapping/Heatmap.hpp" +#include "mapping/OffsetTable.hpp" #include "mapping/One.hpp" #include "mapping/SoA.hpp" #include "mapping/Split.hpp" diff --git a/include/llama/mapping/AoS.hpp b/include/llama/mapping/AoS.hpp index 0ee4bc69d4..ae2826fa6f 100644 --- a/include/llama/mapping/AoS.hpp +++ b/include/llama/mapping/AoS.hpp @@ -45,8 +45,10 @@ namespace llama::mapping * flatSizeOf; } - template - LLAMA_FN_HOST_ACC_INLINE constexpr auto blobNrAndOffset(ArrayDims coord) const -> NrAndOffset + template + LLAMA_FN_HOST_ACC_INLINE constexpr auto blobNrAndOffset( + ArrayDims coord, + Array dynamicArrayExtents = {}) const -> NrAndOffset { constexpr std::size_t flatIndex = #ifdef __NVCC__ diff --git a/include/llama/mapping/AoSoA.hpp b/include/llama/mapping/AoSoA.hpp index d016fab549..529112e0c2 100644 --- a/include/llama/mapping/AoSoA.hpp +++ b/include/llama/mapping/AoSoA.hpp @@ -56,8 +56,10 @@ namespace llama::mapping return LinearizeArrayDimsFunctor{}.size(arrayDimsSize) * sizeOf; } - template - LLAMA_FN_HOST_ACC_INLINE constexpr auto blobNrAndOffset(ArrayDims coord) const -> NrAndOffset + template + LLAMA_FN_HOST_ACC_INLINE constexpr auto blobNrAndOffset( + ArrayDims coord, + Array dynamicArrayExtents = {}) const -> NrAndOffset { const auto flatArrayIndex = LinearizeArrayDimsFunctor{}(coord, arrayDimsSize); const auto blockIndex = flatArrayIndex / Lanes; diff --git a/include/llama/mapping/Heatmap.hpp b/include/llama/mapping/Heatmap.hpp index 34564dca48..92f016a0cc 100644 --- a/include/llama/mapping/Heatmap.hpp +++ b/include/llama/mapping/Heatmap.hpp @@ -44,8 +44,8 @@ namespace llama::mapping return mapping.blobSize(i); } - template - LLAMA_FN_HOST_ACC_INLINE auto blobNrAndOffset(ArrayDims coord) const -> NrAndOffset + template + LLAMA_FN_HOST_ACC_INLINE auto blobNrAndOffset(ArrayDims coord, Array = {}) const -> NrAndOffset { const auto nao = mapping.template blobNrAndOffset(coord); for (auto i = 0; i < sizeof(GetType>); i++) diff --git a/include/llama/mapping/OffsetTable.hpp b/include/llama/mapping/OffsetTable.hpp new file mode 100644 index 0000000000..dda80859d0 --- /dev/null +++ b/include/llama/mapping/OffsetTable.hpp @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "../Tuple.hpp" +#include "AoS.hpp" +#include "Common.hpp" + +namespace llama +{ + using EndOffsetType = std::size_t; + using SizeType = std::size_t; + + template + struct EndOffset + { + }; + template + struct Size + { + }; +} // namespace llama + +namespace llama::mapping +{ + namespace internal + { + using namespace boost::mp11; + + template + inline constexpr bool isEndOffsetField = false; + + template + inline constexpr bool isEndOffsetField> = true; + + template + inline constexpr bool isSizeField = false; + + template + inline constexpr bool isSizeField> = true; + + template + struct AddOffsetAndSizeFieldsImpl + { + using type = Record; + }; + + template + struct AddOffsetAndSizeFieldsImpl> + { + using type = Record, Field, EndOffsetType>, Field, SizeType>>; + }; + + template + using AddOffsetAndSizeFields = typename AddOffsetAndSizeFieldsImpl::type; + + template + struct ReplaceDynamicSubarrays + { + using Replaced = T; + using SubRecordDims = mp_list<>; + using SplitCoords = mp_list<>; + using Augmented = T; + }; + + template + struct ReplaceDynamicSubarrays> + { + using Replaced = EndOffsetType; // offset table entry + using SubRecordDims = mp_list>::Replaced>; + using SplitCoords = mp_push_front< + typename ReplaceDynamicSubarrays>::SplitCoords, + RecordCoord>; + using Augmented = T[]; + }; + + template + struct ReplaceDynamicSubarraysHelp; + + template + struct ReplaceDynamicSubarraysHelp, std::index_sequence> + { + using Replaced = Record>, + typename ReplaceDynamicSubarrays>, RecordCoord>::Replaced>...>; + using SubRecordDims + = mp_append>, RecordCoord>:: + SubRecordDims...>; + using SplitCoords + = mp_append>, RecordCoord>:: + SplitCoords...>; + + using Augmented = mp_flatten>; + }; + + template + struct ReplaceDynamicSubarrays, RecordCoord> + : ReplaceDynamicSubarraysHelp< + Record, + RecordCoord, + std::make_index_sequence> + { + }; + + template + using BeforeDynamic + = RecordCoordFromList>>>; + + template + using AfterDynamic = RecordCoordFromList>::value + 1, RC::size)>>>; + + template + using OffsetLastCoord = RecordCoordFromList< + mp_push_back, mp_size_t>>; + + template + struct ShiftRecordCoord; + + template + struct ShiftRecordCoord> + { + using Coord = RecordCoord<>; + }; + + template + struct ShiftRecordCoord> + { + template + using IsUnboundArrayField = llama::internal::is_unbounded_array>; + + using ShiftedFirst + = RecordCoord, IsUnboundArrayField>::value>; + using ShiftedRest = typename ShiftRecordCoord, RecordCoord>::Coord; + + using Coord = Cat; + }; + } // namespace internal + + /// A type list containing mappings. + template