SIMD
This commit is contained in:
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -17,7 +17,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
target: [linux-x64, linux-arm64, wasm]
|
target: [linux-x64]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,11 @@ include(FetchContent)
|
|||||||
|
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Force static libs")
|
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Force static libs")
|
||||||
|
|
||||||
|
set(HWY_ENABLE_TESTS OFF CACHE BOOL "Disable Highway tests" FORCE)
|
||||||
|
set(HWY_ENABLE_EXAMPLES OFF CACHE BOOL "Disable Highway examples" FORCE)
|
||||||
|
set(HWY_ENABLE_CONTRIB OFF CACHE BOOL "Disable Highway contrib" FORCE)
|
||||||
|
set(HWY_ENABLE_INSTALL OFF CACHE BOOL "Disable Highway install rules" FORCE)
|
||||||
|
|
||||||
set(ZLIB_USE_STATIC_LIBS ON)
|
set(ZLIB_USE_STATIC_LIBS ON)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(zstd CONFIG REQUIRED)
|
find_package(zstd CONFIG REQUIRED)
|
||||||
@ -74,6 +79,12 @@ FetchContent_Declare(
|
|||||||
EXCLUDE_FROM_ALL
|
EXCLUDE_FROM_ALL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
highway
|
||||||
|
GIT_REPOSITORY https://github.com/google/highway.git
|
||||||
|
GIT_TAG 1.3.0
|
||||||
|
)
|
||||||
|
|
||||||
set(MI_OVERRIDE ON CACHE BOOL "" FORCE)
|
set(MI_OVERRIDE ON CACHE BOOL "" FORCE)
|
||||||
set(MI_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
set(MI_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||||
set(MI_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
set(MI_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
@ -88,4 +99,4 @@ set(HTTPLIB_COMPILE OFF CACHE BOOL "" FORCE)
|
|||||||
set(HTTPLIB_TEST OFF CACHE BOOL "" FORCE)
|
set(HTTPLIB_TEST OFF CACHE BOOL "" FORCE)
|
||||||
set(HTTPLIB_EXAMPLE OFF CACHE BOOL "" FORCE)
|
set(HTTPLIB_EXAMPLE OFF CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(httplib pugixml nlohmann_json glaze simdjson tl-expected unordered_dense mimalloc)
|
FetchContent_MakeAvailable(httplib pugixml nlohmann_json glaze simdjson tl-expected unordered_dense mimalloc highway)
|
||||||
|
|||||||
@ -36,6 +36,14 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64")
|
||||||
|
set(IACORE_ARCH_X64 TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64")
|
||||||
|
set(IACORE_ARCH_ARM64 TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "wasm32|emscripten")
|
||||||
|
set(IACORE_ARCH_WASM TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
add_compile_options(/W4)
|
add_compile_options(/W4)
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
set(SRC_FILES
|
set(SRC_FILES
|
||||||
"imp/cpp/IPC.cpp"
|
"imp/cpp/IPC.cpp"
|
||||||
"imp/cpp/XML.cpp"
|
"imp/cpp/XML.cpp"
|
||||||
|
"imp/cpp/SIMD.cpp"
|
||||||
"imp/cpp/JSON.cpp"
|
"imp/cpp/JSON.cpp"
|
||||||
"imp/cpp/IACore.cpp"
|
"imp/cpp/IACore.cpp"
|
||||||
"imp/cpp/Logger.cpp"
|
"imp/cpp/Logger.cpp"
|
||||||
@ -22,6 +23,7 @@ target_include_directories(IACore PUBLIC inc/)
|
|||||||
target_include_directories(IACore PRIVATE imp/hpp/)
|
target_include_directories(IACore PRIVATE imp/hpp/)
|
||||||
|
|
||||||
target_link_libraries(IACore PUBLIC
|
target_link_libraries(IACore PUBLIC
|
||||||
|
hwy
|
||||||
ZLIB::ZLIB
|
ZLIB::ZLIB
|
||||||
zstd::libzstd
|
zstd::libzstd
|
||||||
tl::expected
|
tl::expected
|
||||||
@ -71,3 +73,20 @@ target_compile_definitions(IACore PUBLIC
|
|||||||
$<$<CONFIG:Debug>:__IA_DEBUG=1>
|
$<$<CONFIG:Debug>:__IA_DEBUG=1>
|
||||||
$<$<CONFIG:Release>:__IA_DEBUG=0>
|
$<$<CONFIG:Release>:__IA_DEBUG=0>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(IACORE_ARCH_X64)
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(IACore INTERFACE /arch:AVX2)
|
||||||
|
else()
|
||||||
|
target_compile_options(IACore INTERFACE -mavx2 -mfma)
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(IACore INTERFACE HWY_BASELINE_TARGETS=HWY_AVX2)
|
||||||
|
elseif(IACORE_ARCH_ARM64)
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_compile_options(IACore INTERFACE -march=armv8-a+simd)
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(IACore INTERFACE HWY_BASELINE_TARGETS=HWY_NEON)
|
||||||
|
elseif(IACORE_ARCH_WASM)
|
||||||
|
target_compile_options(IACore INTERFACE -msimd128)
|
||||||
|
target_compile_definitions(IACore INTERFACE HWY_BASELINE_TARGETS=HWY_WASM)
|
||||||
|
endif()
|
||||||
21
Src/IACore/imp/cpp/SIMD.cpp
Normal file
21
Src/IACore/imp/cpp/SIMD.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <IACore/SIMD.hpp>
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@ -189,6 +189,7 @@
|
|||||||
# define OVERRIDE override
|
# define OVERRIDE override
|
||||||
# define CONSTEXPR constexpr
|
# define CONSTEXPR constexpr
|
||||||
# define CONSTEVAL consteval
|
# define CONSTEVAL consteval
|
||||||
|
# define EXPLICIT explicit
|
||||||
# define NOEXCEPT noexcept
|
# define NOEXCEPT noexcept
|
||||||
# define NULLPTR nullptr
|
# define NULLPTR nullptr
|
||||||
# define IA_MOVE(...) std::move(__VA_ARGS__)
|
# define IA_MOVE(...) std::move(__VA_ARGS__)
|
||||||
@ -199,6 +200,7 @@
|
|||||||
# define OVERRIDE
|
# define OVERRIDE
|
||||||
# define CONSTEXPR const
|
# define CONSTEXPR const
|
||||||
# define CONSTEVAL
|
# define CONSTEVAL
|
||||||
|
# define EXPLICIT
|
||||||
# define NOEXCEPT
|
# define NOEXCEPT
|
||||||
# define NULLPTR NULL
|
# define NULLPTR NULL
|
||||||
# define IA_MOVE(...) (__VA_ARGS__)
|
# define IA_MOVE(...) (__VA_ARGS__)
|
||||||
@ -241,7 +243,7 @@
|
|||||||
#define __INTERNAL_IA_STRINGIFY(value) #value
|
#define __INTERNAL_IA_STRINGIFY(value) #value
|
||||||
#define IA_STRINGIFY(value) __INTERNAL_IA_STRINGIFY(value)
|
#define IA_STRINGIFY(value) __INTERNAL_IA_STRINGIFY(value)
|
||||||
|
|
||||||
#define ALIGN(a) __attribute__((aligned(a)))
|
#define ALIGN(a) alignas(a)
|
||||||
|
|
||||||
#define ASM(...) __asm__ volatile(__VA_ARGS__)
|
#define ASM(...) __asm__ volatile(__VA_ARGS__)
|
||||||
|
|
||||||
|
|||||||
318
Src/IACore/inc/IACore/SIMD.hpp
Normal file
318
Src/IACore/inc/IACore/SIMD.hpp
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <IACore/PCH.hpp>
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
# pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <hwy/highway.h>
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
namespace hn = hwy::HWY_NAMESPACE;
|
||||||
|
|
||||||
|
#if HWY_TARGET == HWY_SCALAR
|
||||||
|
# pragma message("Warning: Configuration mismatch. IACore is being compiled for SCALAR SIMD (Slow)")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class ALIGN(16) IntVec4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IntVec4() = default;
|
||||||
|
|
||||||
|
INLINE EXPLICIT IntVec4(IN UINT32 s);
|
||||||
|
INLINE EXPLICIT IntVec4(IN PCUINT32 values);
|
||||||
|
INLINE EXPLICIT IntVec4(IN UINT32 a, IN UINT32 b, IN UINT32 c, IN UINT32 d);
|
||||||
|
|
||||||
|
INLINE IntVec4 operator+(IN CONST IntVec4 &other) CONST;
|
||||||
|
INLINE IntVec4 operator-(IN CONST IntVec4 &other) CONST;
|
||||||
|
INLINE IntVec4 operator*(IN CONST IntVec4 &other) CONST;
|
||||||
|
|
||||||
|
INLINE IntVec4 operator&(IN CONST IntVec4 &other) CONST;
|
||||||
|
INLINE IntVec4 operator|(IN CONST IntVec4 &other) CONST;
|
||||||
|
INLINE IntVec4 operator^(IN CONST IntVec4 &other) CONST;
|
||||||
|
INLINE IntVec4 operator~() CONST;
|
||||||
|
|
||||||
|
INLINE IntVec4 operator<<(IN UINT32 amount) CONST;
|
||||||
|
INLINE IntVec4 operator>>(IN UINT32 amount) CONST;
|
||||||
|
|
||||||
|
INLINE IntVec4 SatAdd(IN CONST IntVec4 &other) CONST;
|
||||||
|
INLINE IntVec4 SatSub(IN CONST IntVec4 &other) CONST;
|
||||||
|
|
||||||
|
INLINE IntVec4 Clamp(IN UINT32 min, IN UINT32 max) CONST;
|
||||||
|
|
||||||
|
INLINE IntVec4 MultAdd(IN CONST IntVec4 &multiplier, IN CONST IntVec4 &addend) CONST;
|
||||||
|
|
||||||
|
INLINE VOID Store(OUT PUINT32 values);
|
||||||
|
STATIC INLINE IntVec4 Load(IN PCUINT32 values);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Tag = hn::FixedTag<UINT32, 4>;
|
||||||
|
|
||||||
|
hn::Vec<Tag> m_data;
|
||||||
|
|
||||||
|
INLINE EXPLICIT IntVec4(hn::Vec<Tag> v) : m_data(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ALIGN(16) FloatVec4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FloatVec4() = default;
|
||||||
|
|
||||||
|
INLINE EXPLICIT FloatVec4(IN FLOAT32 s);
|
||||||
|
INLINE EXPLICIT FloatVec4(IN PCFLOAT32 values);
|
||||||
|
INLINE EXPLICIT FloatVec4(IN FLOAT32 a, IN FLOAT32 b, IN FLOAT32 c, IN FLOAT32 d);
|
||||||
|
|
||||||
|
INLINE FloatVec4 operator+(IN CONST FloatVec4 &other) CONST;
|
||||||
|
INLINE FloatVec4 operator-(IN CONST FloatVec4 &other) CONST;
|
||||||
|
INLINE FloatVec4 operator*(IN CONST FloatVec4 &other) CONST;
|
||||||
|
INLINE FloatVec4 operator/(IN CONST FloatVec4 &other) CONST;
|
||||||
|
|
||||||
|
INLINE FloatVec4 Clamp(IN FLOAT32 min, IN FLOAT32 max) CONST;
|
||||||
|
|
||||||
|
INLINE FloatVec4 Abs() CONST;
|
||||||
|
INLINE FloatVec4 Sqrt() CONST;
|
||||||
|
INLINE FloatVec4 Rsqrt() CONST;
|
||||||
|
INLINE FloatVec4 Normalize() CONST;
|
||||||
|
|
||||||
|
INLINE FLOAT32 Dot(IN CONST FloatVec4 &other) CONST;
|
||||||
|
|
||||||
|
INLINE FloatVec4 MultAdd(IN CONST FloatVec4 &multiplier, IN CONST FloatVec4 &addend) CONST;
|
||||||
|
|
||||||
|
INLINE VOID Store(OUT PFLOAT32 values);
|
||||||
|
STATIC INLINE FloatVec4 Load(IN PCFLOAT32 values);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Tag = hn::FixedTag<FLOAT32, 4>;
|
||||||
|
|
||||||
|
hn::Vec<Tag> m_data;
|
||||||
|
|
||||||
|
INLINE EXPLICIT FloatVec4(hn::Vec<Tag> v) : m_data(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace IACore
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
IntVec4::IntVec4(IN UINT32 s)
|
||||||
|
{
|
||||||
|
CONST Tag d;
|
||||||
|
m_data = hn::Set(d, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4::IntVec4(IN PCUINT32 values)
|
||||||
|
{
|
||||||
|
CONST Tag data;
|
||||||
|
m_data = hn::Load(data, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4::IntVec4(IN UINT32 a, IN UINT32 b, IN UINT32 c, IN UINT32 d)
|
||||||
|
{
|
||||||
|
CONST Tag data;
|
||||||
|
ALIGN(16) UINT32 values[4] = {a, b, c, d};
|
||||||
|
m_data = hn::Load(data, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator+(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::Add(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator-(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::Sub(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator*(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::Mul(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator&(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::And(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator|(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::Or(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator^(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::Xor(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator~() CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::Not(m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator<<(IN UINT32 amount) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::ShiftLeftSame(m_data, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::operator>>(IN UINT32 amount) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::ShiftRightSame(m_data, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::MultAdd(IN CONST IntVec4 &multiplier, IN CONST IntVec4 &addend) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::MulAdd(m_data, multiplier.m_data, addend.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::SatAdd(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::SaturatedAdd(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::SatSub(IN CONST IntVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return IntVec4(hn::SaturatedSub(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::Clamp(IN UINT32 min, IN UINT32 max) CONST
|
||||||
|
{
|
||||||
|
CONST Tag d;
|
||||||
|
auto vMin = hn::Set(d, min);
|
||||||
|
auto vMax = hn::Set(d, max);
|
||||||
|
return IntVec4(hn::Min(hn::Max(m_data, vMin), vMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID IntVec4::Store(OUT PUINT32 values)
|
||||||
|
{
|
||||||
|
CONST Tag d;
|
||||||
|
hn::Store(m_data, d, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntVec4 IntVec4::Load(IN PCUINT32 values)
|
||||||
|
{
|
||||||
|
CONST Tag d;
|
||||||
|
return IntVec4(hn::Load(d, values));
|
||||||
|
}
|
||||||
|
} // namespace IACore
|
||||||
|
|
||||||
|
namespace IACore
|
||||||
|
{
|
||||||
|
FloatVec4::FloatVec4(IN FLOAT32 s)
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
m_data = hn::Set(d, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4::FloatVec4(IN PCFLOAT32 values)
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
m_data = hn::Load(d, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4::FloatVec4(IN FLOAT32 a, IN FLOAT32 b, IN FLOAT32 c, IN FLOAT32 d)
|
||||||
|
{
|
||||||
|
const Tag data;
|
||||||
|
ALIGN(16) FLOAT32 temp[4] = {a, b, c, d};
|
||||||
|
m_data = hn::Load(data, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::operator+(IN CONST FloatVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::Add(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::operator-(IN CONST FloatVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::Sub(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::operator*(IN CONST FloatVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::Mul(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::operator/(IN CONST FloatVec4 &other) CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::Div(m_data, other.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::MultAdd(IN CONST FloatVec4 &multiplier, IN CONST FloatVec4 &addend) CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::MulAdd(m_data, multiplier.m_data, addend.m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::Clamp(IN FLOAT32 min, IN FLOAT32 max) CONST
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
auto vMin = hn::Set(d, min);
|
||||||
|
auto vMax = hn::Set(d, max);
|
||||||
|
return FloatVec4(hn::Min(hn::Max(m_data, vMin), vMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::Sqrt() CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::Sqrt(m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::Rsqrt() CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::ApproximateReciprocalSqrt(m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::Abs() CONST
|
||||||
|
{
|
||||||
|
return FloatVec4(hn::Abs(m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
FLOAT32 FloatVec4::Dot(IN CONST FloatVec4 &other) CONST
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
auto vMul = hn::Mul(m_data, other.m_data);
|
||||||
|
return hn::ReduceSum(d, vMul);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::Normalize() CONST
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
auto vMul = hn::Mul(m_data, m_data);
|
||||||
|
auto vLenSq = hn::SumOfLanes(d, vMul);
|
||||||
|
auto vInvLen = hn::ApproximateReciprocalSqrt(vLenSq);
|
||||||
|
return FloatVec4(hn::Mul(m_data, vInvLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FloatVec4::Store(OUT PFLOAT32 values)
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
hn::Store(m_data, d, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatVec4 FloatVec4::Load(IN PCFLOAT32 values)
|
||||||
|
{
|
||||||
|
const Tag d;
|
||||||
|
return FloatVec4(hn::Load(d, values));
|
||||||
|
}
|
||||||
|
} // namespace IACore
|
||||||
@ -20,6 +20,9 @@ set(TEST_SOURCES
|
|||||||
ProcessOps.cpp
|
ProcessOps.cpp
|
||||||
StreamReader.cpp
|
StreamReader.cpp
|
||||||
RingBuffer.cpp
|
RingBuffer.cpp
|
||||||
|
|
||||||
|
SIMD/IntVec4.cpp
|
||||||
|
SIMD/FloatVec4.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(IACore_Test_Suite ${TEST_SOURCES})
|
add_executable(IACore_Test_Suite ${TEST_SOURCES})
|
||||||
|
|||||||
106
Tests/Unit/SIMD/FloatVec4.cpp
Normal file
106
Tests/Unit/SIMD/FloatVec4.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <IACore/SIMD.hpp>
|
||||||
|
#include <IACore/IATest.hpp>
|
||||||
|
|
||||||
|
using namespace IACore;
|
||||||
|
|
||||||
|
IAT_BEGIN_BLOCK(Core, FloatVec4)
|
||||||
|
|
||||||
|
BOOL TestFloatArithmetic()
|
||||||
|
{
|
||||||
|
FloatVec4 v1(10.0f, 20.0f, 30.0f, 40.0f);
|
||||||
|
FloatVec4 v2(2.0f, 4.0f, 5.0f, 8.0f);
|
||||||
|
|
||||||
|
ALIGN(16) FLOAT32 res[4];
|
||||||
|
|
||||||
|
(v1 / v2).Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 5.0f);
|
||||||
|
IAT_CHECK_APPROX(res[3], 5.0f);
|
||||||
|
|
||||||
|
(v1 * v2).Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 20.0f);
|
||||||
|
|
||||||
|
(v1 + v2).Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 12.0f);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestMathHelpers()
|
||||||
|
{
|
||||||
|
ALIGN(16) FLOAT32 res[4];
|
||||||
|
|
||||||
|
FloatVec4 vSq(4.0f, 9.0f, 16.0f, 25.0f);
|
||||||
|
vSq.Sqrt().Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 2.0f);
|
||||||
|
IAT_CHECK_APPROX(res[3], 5.0f);
|
||||||
|
|
||||||
|
FloatVec4 vNeg(-1.0f, -5.0f, 10.0f, -0.0f);
|
||||||
|
vNeg.Abs().Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 1.0f);
|
||||||
|
IAT_CHECK_APPROX(res[2], 10.0f);
|
||||||
|
|
||||||
|
FloatVec4 vClamp(-100.0f, 0.0f, 50.0f, 200.0f);
|
||||||
|
vClamp.Clamp(0.0f, 100.0f).Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 0.0f);
|
||||||
|
IAT_CHECK_APPROX(res[2], 50.0f);
|
||||||
|
IAT_CHECK_APPROX(res[3], 100.0f);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestApproxMath()
|
||||||
|
{
|
||||||
|
ALIGN(16) FLOAT32 res[4];
|
||||||
|
FloatVec4 v(16.0f, 25.0f, 100.0f, 1.0f);
|
||||||
|
|
||||||
|
v.Rsqrt().Store(res);
|
||||||
|
|
||||||
|
IAT_CHECK_APPROX(res[0], 0.25f);
|
||||||
|
IAT_CHECK_APPROX(res[2], 0.1f);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestLinearAlgebra()
|
||||||
|
{
|
||||||
|
FloatVec4 v1(1.0f, 2.0f, 3.0f, 4.0f);
|
||||||
|
FloatVec4 v2(1.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
FLOAT32 dot = v1.Dot(v2);
|
||||||
|
IAT_CHECK_APPROX(dot, 4.0f);
|
||||||
|
|
||||||
|
FloatVec4 vNorm(10.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
ALIGN(16) FLOAT32 res[4];
|
||||||
|
|
||||||
|
vNorm.Normalize().Store(res);
|
||||||
|
IAT_CHECK_APPROX(res[0], 1.0f);
|
||||||
|
IAT_CHECK_APPROX(res[1], 0.0f);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAT_BEGIN_TEST_LIST()
|
||||||
|
IAT_ADD_TEST(TestFloatArithmetic);
|
||||||
|
IAT_ADD_TEST(TestMathHelpers);
|
||||||
|
IAT_ADD_TEST(TestApproxMath);
|
||||||
|
IAT_ADD_TEST(TestLinearAlgebra);
|
||||||
|
IAT_END_TEST_LIST()
|
||||||
|
|
||||||
|
IAT_END_BLOCK()
|
||||||
|
|
||||||
|
IAT_REGISTER_ENTRY(Core, FloatVec4)
|
||||||
152
Tests/Unit/SIMD/IntVec4.cpp
Normal file
152
Tests/Unit/SIMD/IntVec4.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||||
|
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||||
|
|
||||||
|
#include <IACore/SIMD.hpp>
|
||||||
|
#include <IACore/IATest.hpp>
|
||||||
|
|
||||||
|
using namespace IACore;
|
||||||
|
|
||||||
|
IAT_BEGIN_BLOCK(Core, IntVec4)
|
||||||
|
|
||||||
|
BOOL TestConstructors()
|
||||||
|
{
|
||||||
|
IntVec4 vBroadcast(10);
|
||||||
|
ALIGN(16) UINT32 storeBuf[4];
|
||||||
|
vBroadcast.Store(storeBuf);
|
||||||
|
|
||||||
|
IAT_CHECK_EQ(storeBuf[0], 10U);
|
||||||
|
IAT_CHECK_EQ(storeBuf[3], 10U);
|
||||||
|
|
||||||
|
IntVec4 vComp(1, 2, 3, 4);
|
||||||
|
vComp.Store(storeBuf);
|
||||||
|
IAT_CHECK_EQ(storeBuf[0], 1U);
|
||||||
|
IAT_CHECK_EQ(storeBuf[3], 4U);
|
||||||
|
|
||||||
|
ALIGN(16) UINT32 srcBuf[4] = {100, 200, 300, 400};
|
||||||
|
IntVec4 vLoad = IntVec4::Load(srcBuf);
|
||||||
|
vLoad.Store(storeBuf);
|
||||||
|
IAT_CHECK_EQ(storeBuf[1], 200U);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestArithmetic()
|
||||||
|
{
|
||||||
|
IntVec4 v1(10, 20, 30, 40);
|
||||||
|
IntVec4 v2(1, 2, 3, 4);
|
||||||
|
|
||||||
|
IntVec4 vAdd = v1 + v2;
|
||||||
|
ALIGN(16) UINT32 res[4];
|
||||||
|
vAdd.Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 11U);
|
||||||
|
IAT_CHECK_EQ(res[3], 44U);
|
||||||
|
|
||||||
|
IntVec4 vSub = v1 - v2;
|
||||||
|
vSub.Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 9U);
|
||||||
|
|
||||||
|
IntVec4 vMul = v1 * v2;
|
||||||
|
vMul.Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 10U);
|
||||||
|
IAT_CHECK_EQ(res[2], 90U);
|
||||||
|
IAT_CHECK_EQ(res[3], 160U);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestBitwise()
|
||||||
|
{
|
||||||
|
IntVec4 vAllOnes(0xFFFFFFFF);
|
||||||
|
IntVec4 vZero((UINT32) 0);
|
||||||
|
IntVec4 vPattern(0xAAAAAAAA);
|
||||||
|
|
||||||
|
ALIGN(16) UINT32 res[4];
|
||||||
|
|
||||||
|
(vAllOnes & vPattern).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 0xAAAAAAAAU);
|
||||||
|
|
||||||
|
(vZero | vPattern).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 0xAAAAAAAAU);
|
||||||
|
|
||||||
|
(vAllOnes ^ vPattern).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 0x55555555U);
|
||||||
|
|
||||||
|
(~vPattern).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 0x55555555U);
|
||||||
|
|
||||||
|
IntVec4 vShift(1);
|
||||||
|
(vShift << 1).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 2U);
|
||||||
|
|
||||||
|
IntVec4 vShiftRight(4);
|
||||||
|
(vShiftRight >> 1).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 2U);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestSaturation()
|
||||||
|
{
|
||||||
|
UINT32 max = 0xFFFFFFFF;
|
||||||
|
IntVec4 vHigh(max - 10);
|
||||||
|
IntVec4 vAdd(20);
|
||||||
|
|
||||||
|
ALIGN(16) UINT32 res[4];
|
||||||
|
|
||||||
|
vHigh.SatAdd(vAdd).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], max);
|
||||||
|
|
||||||
|
IntVec4 vLow(10);
|
||||||
|
IntVec4 vSub(20);
|
||||||
|
vLow.SatSub(vSub).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 0U);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TestAdvancedOps()
|
||||||
|
{
|
||||||
|
IntVec4 v(0, 50, 100, 150);
|
||||||
|
ALIGN(16) UINT32 res[4];
|
||||||
|
|
||||||
|
v.Clamp(40, 110).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 40U);
|
||||||
|
IAT_CHECK_EQ(res[1], 50U);
|
||||||
|
IAT_CHECK_EQ(res[2], 100U);
|
||||||
|
IAT_CHECK_EQ(res[3], 110U);
|
||||||
|
|
||||||
|
IntVec4 A(2);
|
||||||
|
IntVec4 B(10);
|
||||||
|
IntVec4 C(5);
|
||||||
|
A.MultAdd(B, C).Store(res);
|
||||||
|
IAT_CHECK_EQ(res[0], 25U);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAT_BEGIN_TEST_LIST()
|
||||||
|
IAT_ADD_TEST(TestConstructors);
|
||||||
|
IAT_ADD_TEST(TestArithmetic);
|
||||||
|
IAT_ADD_TEST(TestBitwise);
|
||||||
|
IAT_ADD_TEST(TestSaturation);
|
||||||
|
IAT_ADD_TEST(TestAdvancedOps);
|
||||||
|
IAT_END_TEST_LIST()
|
||||||
|
|
||||||
|
IAT_END_BLOCK()
|
||||||
|
|
||||||
|
IAT_REGISTER_ENTRY(Core, IntVec4)
|
||||||
Reference in New Issue
Block a user