| // SPDX-FileCopyrightText: The Eigen Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_SPARSE_SCATTER_H | |
| #define EIGEN_SPARSE_SCATTER_H | |
| // IWYU pragma: private | |
| #include "./InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| constexpr Index kSparseScatterPacketMinSize = 32; | |
| template <typename Scalar, bool Vectorize> | |
| struct sparse_scatter_sub_impl { | |
| template <typename StorageIndex, typename ValuesEvaluator> | |
| static EIGEN_STRONG_INLINE Index run(Scalar*, const StorageIndex*, const ValuesEvaluator&, Index) { | |
| return 0; | |
| } | |
| }; | |
| template <typename Scalar> | |
| struct sparse_scatter_sub_impl<Scalar, true> { | |
| // Keep the packet loop out of the common path for short updates. | |
| template <typename StorageIndex, typename ValuesEvaluator> | |
| static EIGEN_DONT_INLINE Index run(Scalar* EIGEN_RESTRICT dense, const StorageIndex* indices, | |
| const ValuesEvaluator& values, Index size) { | |
| // Limit register pressure from the indirect addresses. | |
| using Packet = typename find_best_packet<Scalar, 4>::type; | |
| constexpr Index PacketSize = unpacket_traits<Packet>::size; | |
| const Index end = size - size % PacketSize; | |
| for (Index i = 0; i < end; i += PacketSize) { | |
| EIGEN_ALIGN_MAX Scalar gathered[PacketSize]; | |
| for (Index lane = 0; lane < PacketSize; ++lane) gathered[lane] = dense[indices[i + lane]]; | |
| pstoreu(gathered, psub(ploadu<Packet>(gathered), values.template packet<Unaligned, Packet>(i))); | |
| for (Index lane = 0; lane < PacketSize; ++lane) dense[indices[i + lane]] = gathered[lane]; | |
| } | |
| return end; | |
| } | |
| }; | |
| // Subtract a packet-sized prefix of values from dense at distinct indices, returning its length. | |
| // Neither input may alias dense. Callers retain their scalar loop for short updates and the tail. | |
| // Packing complex destinations costs more than the packet arithmetic saves. | |
| template <typename Scalar, typename StorageIndex, typename Values> | |
| EIGEN_STRONG_INLINE Index sparse_scatter_sub_packets(Scalar* EIGEN_RESTRICT dense, const StorageIndex* indices, | |
| const MatrixBase<Values>& values) { | |
| EIGEN_STATIC_ASSERT_VECTOR_ONLY(Values) | |
| EIGEN_STATIC_ASSERT((std::is_same<Scalar, typename Values::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES) | |
| constexpr bool Vectorize = (evaluator<Values>::Flags & PacketAccessBit) && | |
| (evaluator<Values>::Flags & LinearAccessBit) && packet_traits<Scalar>::HasSub && | |
| !NumTraits<Scalar>::IsComplex; | |
| if (!Vectorize || values.size() < kSparseScatterPacketMinSize) return 0; | |
| evaluator<Values> valuesEval(values.derived()); | |
| return sparse_scatter_sub_impl<Scalar, Vectorize>::run(dense, indices, valuesEval, values.size()); | |
| } | |
| template <bool Conjugate, typename Scalar, typename StorageIndex> | |
| EIGEN_STRONG_INLINE Index sparse_scatter_sub_packets(Scalar* dense, const StorageIndex* indices, const Scalar* values, | |
| Index size, const Scalar& scale) { | |
| constexpr bool Vectorize = packet_traits<Scalar>::Vectorizable && packet_traits<Scalar>::HasMul && | |
| packet_traits<Scalar>::HasSub && !NumTraits<Scalar>::IsComplex; | |
| if (!Vectorize || size < kSparseScatterPacketMinSize) return 0; | |
| const Map<const Matrix<Scalar, Dynamic, 1>> mappedValues(values, size); | |
| return sparse_scatter_sub_packets(dense, indices, mappedValues.template conjugateIf<Conjugate>() * scale); | |
| } | |
| } // namespace internal | |
| } // namespace Eigen | |
| #endif // EIGEN_SPARSE_SCATTER_H |