Program Listing for File simd_avx.h

Return to documentation for file (framework/simd/simd_avx.h)

// SPDX-FileCopyrightText: 2026 The OpenSn Authors <https://open-sn.github.io/opensn/>
// SPDX-License-Identifier: MIT

#pragma once

#include <cstddef>
#include <cstdint>
#include <immintrin.h>

// NOLINTBEGIN(portability-simd-intrinsics,cppcoreguidelines-pro-type-reinterpret-cast)
namespace opensn
{

struct SimdTraits
{
  using register_type = __m256d;
  using index_type = __m256i;
  static constexpr std::size_t size = 4;
  static constexpr std::size_t register_alignment = alignof(register_type);
  static constexpr std::size_t index_alignment = alignof(index_type);
};

} // namespace opensn

#include "framework/simd/simd_impl.h"

namespace opensn
{

inline SimdIndex::SimdIndex(const value_type* src)
  : value_(_mm256_loadu_si256(reinterpret_cast<const __m256i*>(src)))
{
}

inline SimdIndex::register_type
SimdIndex::native() const
{
  return value_;
}

inline Simd::Simd() : value_(_mm256_setzero_pd())
{
}

inline Simd::Simd(double value) : value_(_mm256_set1_pd(value))
{
}

inline Simd::Simd(const double* src) : value_(_mm256_loadu_pd(src))
{
}

inline void
Simd::LoadUnaligned(const double* src)
{
  value_ = _mm256_loadu_pd(src);
}

inline void
Simd::StoreUnaligned(double* dst) const
{
  _mm256_storeu_pd(dst, value_);
}

inline Simd
Simd::Gather(const double* src, const SimdIndex& index)
{
#if defined(__AVX2__)
  Simd result;
  result.value_ = _mm256_i64gather_pd(src, index.value_, static_cast<int>(sizeof(double)));
  return result;
#else
  alignas(SimdTraits::index_alignment) std::int64_t indices[size];
  alignas(SimdTraits::register_alignment) double values[size];
  _mm256_storeu_si256(reinterpret_cast<__m256i*>(indices), index.value_);
  for (std::size_t i = 0; i < size; ++i)
    values[i] = src[indices[i]];
  return Simd(values);
#endif
}

inline void
Simd::Scatter(double* dst, const SimdIndex& index) const
{
  alignas(SimdTraits::index_alignment) std::int64_t indices[size];
  alignas(SimdTraits::register_alignment) double values[size];
  _mm256_storeu_si256(reinterpret_cast<__m256i*>(indices), index.value_);
  _mm256_storeu_pd(values, value_);
  for (std::size_t i = 0; i < size; ++i)
    dst[indices[i]] = values[i];
}

inline Simd::register_type
Simd::native() const
{
  return value_;
}

inline Simd&
Simd::operator+=(const Simd& other)
{
  value_ = _mm256_add_pd(value_, other.value_);
  return *this;
}

inline Simd&
Simd::operator-=(const Simd& other)
{
  value_ = _mm256_sub_pd(value_, other.value_);
  return *this;
}

inline Simd&
Simd::operator*=(const Simd& other)
{
  value_ = _mm256_mul_pd(value_, other.value_);
  return *this;
}

inline Simd&
Simd::operator/=(const Simd& other)
{
  value_ = _mm256_div_pd(value_, other.value_);
  return *this;
}

inline Simd
Simd::Fma(const Simd& a, const Simd& b, const Simd& c)
{
  Simd result;
#if defined(__FMA__)
  result.value_ = _mm256_fmadd_pd(a.value_, b.value_, c.value_);
#else
  result.value_ = _mm256_add_pd(_mm256_mul_pd(a.value_, b.value_), c.value_);
#endif
  return result;
}

inline Simd
Simd::Fnma(const Simd& a, const Simd& b, const Simd& c)
{
  Simd result;
#if defined(__FMA__)
  result.value_ = _mm256_fnmadd_pd(a.value_, b.value_, c.value_);
#else
  result.value_ = _mm256_sub_pd(c.value_, _mm256_mul_pd(a.value_, b.value_));
#endif
  return result;
}

} // namespace opensn
// NOLINTEND(portability-simd-intrinsics,cppcoreguidelines-pro-type-reinterpret-cast)