blob: 0a7c78dcc7f7b4263bb9095b8a20b8b8da46eee1 [file]
// 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