20namespace uni20::linalg::detail::cuda_reference
24enum class ElementwiseIndexKind
38template <std::size_t OperandCount, std::size_t MaximumRank, std::unsigned_integral LogicalIndex,
39 std::signed_integral Offset>
40struct StridedElementwisePlan
42 using logical_index_type = LogicalIndex;
43 using offset_type = Offset;
44 using offsets_type = std::array<offset_type, OperandCount>;
46 static constexpr std::size_t operand_count = OperandCount;
47 static constexpr std::size_t maximum_rank = MaximumRank;
48 static_assert(MaximumRank <= std::numeric_limits<std::uint8_t>::max());
50 logical_index_type element_count = 0;
51 std::uint8_t compact_rank = 0;
52 std::array<logical_index_type, MaximumRank> extents{};
53 std::array<offsets_type, MaximumRank>
strides{};
54 offsets_type base_offsets{};
57 [[nodiscard]]
UNI20_HOST_DEVICE constexpr offsets_type offsets(logical_index_type logical_index)
const noexcept
59 auto result = base_offsets;
60 for (std::size_t dimension = 0; dimension < compact_rank; ++dimension)
62 auto const extent = extents[dimension];
63 auto const coordinate = logical_index % extent;
64 logical_index /= extent;
65 for (std::size_t operand = 0; operand < OperandCount; ++operand)
67 auto const stride =
strides[dimension][operand];
68 if (stride != 0) result[operand] +=
static_cast<offset_type
>(coordinate) * stride;
75template <std::
size_t OperandCount, std::
size_t MaximumRank>
76using StridedElementwisePlan32 = StridedElementwisePlan<OperandCount, MaximumRank, std::uint32_t, std::int32_t>;
78template <std::
size_t OperandCount, std::
size_t MaximumRank>
79using StridedElementwisePlan64 = StridedElementwisePlan<OperandCount, MaximumRank, std::uint64_t, std::int64_t>;
83template <std::
size_t OperandCount, std::
size_t MaximumRank>
struct LoweredStridedElementwisePlan
85 ElementwiseIndexKind index_kind = ElementwiseIndexKind::index_32;
86 StridedElementwisePlan32<OperandCount, MaximumRank> plan_32;
87 StridedElementwisePlan64<OperandCount, MaximumRank> plan_64;
90 [[nodiscard]] std::size_t element_count() const noexcept
92 if (index_kind == ElementwiseIndexKind::index_32)
return plan_32.element_count;
93 return static_cast<std::size_t
>(plan_64.element_count);
99 template <
class Visitor>
decltype(
auto) visit(Visitor&& visitor)
const
101 if (index_kind == ElementwiseIndexKind::index_32)
return std::forward<Visitor>(visitor)(plan_32);
102 return std::forward<Visitor>(visitor)(plan_64);
106namespace elementwise_plan_detail
109template <
class Target,
class Source> [[nodiscard]]
constexpr bool in_range(Source
value)
noexcept
111 return std::in_range<Target>(
value);
114template <
class LogicalIndex,
class Offset, std::
size_t OperandCount, std::
size_t MaximumRank, std::
size_t SourceRank>
115[[nodiscard]]
bool try_lower(multi_iteration_plan<OperandCount, SourceRank>
const& source,
116 StridedElementwisePlan<OperandCount, MaximumRank, LogicalIndex, Offset>& destination)
118 constexpr auto maximum_logical_index = std::numeric_limits<std::make_signed_t<LogicalIndex>>::max();
119 if (!source.representable || source.rank() > MaximumRank ||
120 std::cmp_greater(source.element_count, maximum_logical_index))
123 destination.element_count =
static_cast<LogicalIndex
>(source.element_count);
126 destination.compact_rank = 0;
129 destination.compact_rank =
static_cast<std::uint8_t
>(source.rank());
131 for (std::size_t operand = 0; operand < OperandCount; ++operand)
133 auto const range = source.reachable_offsets[operand];
134 if ((!range.empty() && (range.minimum < 0 || !in_range<Offset>(range.maximum))) ||
135 source.base_offsets[operand] < 0 || !in_range<Offset>(source.base_offsets[operand]))
137 destination.base_offsets[operand] =
static_cast<Offset
>(source.base_offsets[operand]);
140 for (std::size_t device_dimension = 0; device_dimension < source.rank(); ++device_dimension)
142 auto const& source_dimension = source.dimensions[source.rank() - device_dimension - 1];
143 if (source_dimension.extent <= 0 || !in_range<LogicalIndex>(source_dimension.extent))
return false;
144 destination.extents[device_dimension] =
static_cast<LogicalIndex
>(source_dimension.extent);
146 for (std::size_t operand = 0; operand < OperandCount; ++operand)
148 auto const stride = source_dimension.strides[operand];
149 if (stride < 0 || !in_range<Offset>(stride))
return false;
150 destination.strides[device_dimension][operand] =
static_cast<Offset
>(stride);
166template <std::
size_t MaximumRank, std::
size_t OperandCount, std::
size_t SourceRank>
168try_lower_strided_elementwise_plan(multi_iteration_plan<OperandCount, SourceRank>
const& source,
169 LoweredStridedElementwisePlan<OperandCount, MaximumRank>& destination)
171 StridedElementwisePlan32<OperandCount, MaximumRank> plan_32;
172 if (elementwise_plan_detail::try_lower(source, plan_32))
174 destination.index_kind = ElementwiseIndexKind::index_32;
175 destination.plan_32 = plan_32;
179 StridedElementwisePlan64<OperandCount, MaximumRank> plan_64;
180 if (!elementwise_plan_detail::try_lower(source, plan_64))
return false;
181 destination.index_kind = ElementwiseIndexKind::index_64;
182 destination.plan_64 = plan_64;
Project compiler annotations shared by host and device code.
#define UNI20_HOST_DEVICE
Definition compiler_attributes.hpp:12
locale_t value
Definition data_table.cpp:49
auto strides(S const &s)
Retrieve the strides associated with a strided mdspec-like type.
Definition mdspan/concepts.hpp:558
Helpers for constructing merged iteration plans over strided tensors.