Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
1d3a80351a | |||
e0c9b34a5d | |||
f23f6d4583 | |||
42e8738edc |
12 changed files with 335 additions and 6 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Michele "King_DuckZ" Santullo
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Michele "King_DuckZ" Santullo
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef id8949C80C36BA42CABC49EA4C1DB54BC7
|
||||
#define id8949C80C36BA42CABC49EA4C1DB54BC7
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Michele "King_DuckZ" Santullo
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -121,6 +121,45 @@ namespace vwr {
|
|||
};
|
||||
};
|
||||
|
||||
template <std::size_t A, std::size_t... Others>
|
||||
struct Sum {
|
||||
enum {
|
||||
value = A + Sum<Others...>::value
|
||||
};
|
||||
};
|
||||
template <std::size_t A>
|
||||
struct Sum<A> {
|
||||
enum {
|
||||
value = A
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename Seq>
|
||||
struct IsInterleavedMemory;
|
||||
template <typename T, std::size_t... I>
|
||||
struct IsInterleavedMemory<T, bt::index_seq<I...>> {
|
||||
enum {
|
||||
value = Sum<(
|
||||
get_offset_enum_from_index<T, I>::value == I * sizeof(typename VectorWrapperInfo<T>::scalar_type) + get_offset_enum_from_index<T, 0>::value ? 0 : 1
|
||||
)...>::value
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, bool RawDataAccess=HasOffsetXEnum<VectorWrapperInfo<T>>::value>
|
||||
struct WrappedTypeLayoutInfo;
|
||||
template <typename T>
|
||||
struct WrappedTypeLayoutInfo<T, true> {
|
||||
enum {
|
||||
is_interleaved_mem = (IsInterleavedMemory<T, bt::index_range<0, VectorWrapperInfo<T>::dimensions>>::value ? 1 : 0)
|
||||
};
|
||||
};
|
||||
template <typename T>
|
||||
struct WrappedTypeLayoutInfo<T, false> {
|
||||
enum {
|
||||
is_interleaved_mem = 2
|
||||
};
|
||||
};
|
||||
|
||||
template <typename V> struct is_vec {
|
||||
enum { value = false };
|
||||
};
|
||||
|
@ -137,7 +176,8 @@ namespace vwr {
|
|||
typedef typename VectorWrapperInfo<V>::scalar_type scalar_type;
|
||||
|
||||
enum {
|
||||
dimensions = VectorWrapperInfo<V>::dimensions
|
||||
dimensions = VectorWrapperInfo<V>::dimensions,
|
||||
is_interleaved_mem = WrappedTypeLayoutInfo<V>::is_interleaved_mem
|
||||
};
|
||||
|
||||
VecBase ( void ) = default;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Michele "King_DuckZ" Santullo
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
83
include/vectorwrapper/vectorwrapper_simd.hpp
Normal file
83
include/vectorwrapper/vectorwrapper_simd.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef id2996A9D174804F7B88936D6C363D235B
|
||||
#define id2996A9D174804F7B88936D6C363D235B
|
||||
|
||||
#include "vectorwrapper/vectorwrapper.hpp"
|
||||
#include <type_traits>
|
||||
#include <emmintrin.h>
|
||||
|
||||
namespace vwr {
|
||||
namespace simd {
|
||||
template <typename V, std::size_t=::vwr::Vec<V>::dimensions, typename=typename ::vwr::Vec<V>::scalar_type>
|
||||
class Vec;
|
||||
|
||||
template <typename V, std::size_t=::vwr::Vec<V>::dimensions, typename=typename ::vwr::Vec<V>::scalar_type>
|
||||
class VecPack;
|
||||
|
||||
template <typename V>
|
||||
class Vec<V, 3, float> : public implem::VecBase<V>, public implem::VecAccessors<V, 3> {
|
||||
typedef ::vwr::implem::VecBase<V> base_class;
|
||||
public:
|
||||
static_assert(alignof(V) % 16 == 0, "Wrapped type must be aligned to 16");
|
||||
static_assert(base_class::is_interleaved_mem == 0, "Expected tightly packed vector_type");
|
||||
|
||||
using typename base_class::vector_type;
|
||||
typedef VecPack<V, 3, float> pack_type;
|
||||
typedef float scalar_type;
|
||||
|
||||
Vec ( void ) = default;
|
||||
Vec ( const Vec& ) = default;
|
||||
Vec ( VecPack<V, 3, float> parPack ) __attribute__((always_inline));
|
||||
explicit Vec ( const vector_type& parIn ) : base_class(parIn) { }
|
||||
explicit Vec ( const scalar_type parX ) : base_class(parX) { }
|
||||
explicit Vec ( const base_class& parIn ) : base_class(parIn) { }
|
||||
|
||||
Vec& operator= ( VecPack<V, 3, float> parPack ) __attribute__((always_inline));
|
||||
|
||||
template <typename V2> Vec& operator+= ( const Vec<V2, 3, scalar_type>& parOther );
|
||||
template <typename V2> Vec& operator-= ( const Vec<V2, 3, scalar_type>& parOther );
|
||||
template <typename V2> Vec& operator*= ( const Vec<V2, 3, scalar_type>& parOther );
|
||||
template <typename V2> Vec& operator/= ( const Vec<V2, 3, scalar_type>& parOther );
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
class VecPack<V, 3, float> {
|
||||
public:
|
||||
VecPack ( const Vec<V, 3, float>& parVec ) __attribute__((always_inline));
|
||||
VecPack ( __m128 parPack ) __attribute__((always_inline));
|
||||
VecPack ( float parValue ) __attribute__((always_inline));
|
||||
|
||||
__m128 pack;
|
||||
};
|
||||
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator+ ( V1<V, 3, float> parLeft, V2<V, 3, float> parRight ) __attribute__((always_inline));
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator+ ( V1<V, 3, float> parLeft, V2<V, 3, float> parRight ) __attribute__((always_inline));
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator- ( V1<V, 3, float> parLeft, V2<V, 3, float> parRight ) __attribute__((always_inline));
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator* ( V1<V, 3, float> parLeft, V2<V, 3, float> parRight ) __attribute__((always_inline));
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator/ ( V1<V, 3, float> parLeft, V2<V, 3, float> parRight ) __attribute__((always_inline));
|
||||
} //namespace simd
|
||||
} //namespace vwr
|
||||
|
||||
#include "vectorwrapper/vectorwrapper_simd.inl"
|
||||
|
||||
#endif
|
95
include/vectorwrapper/vectorwrapper_simd.inl
Normal file
95
include/vectorwrapper/vectorwrapper_simd.inl
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2015, 2016 Michele "King_DuckZ" Santullo
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace vwr {
|
||||
namespace simd {
|
||||
template <typename V>
|
||||
inline Vec<V, 3, float>::Vec (VecPack<V, 3, float> parPack) {
|
||||
_mm_store_ps(&this->x(), parPack.pack);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
Vec<V, 3, float>& Vec<V, 3, float>::operator= (VecPack<V, 3, float> parPack) {
|
||||
_mm_store_ps(&this->x(), parPack.pack);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
template <typename V2>
|
||||
auto Vec<V, 3, float>::operator+= (const Vec<V2, 3, scalar_type>& parOther) -> Vec& {
|
||||
__m128 pack_this;
|
||||
__m128 pack_other;
|
||||
|
||||
pack_this = _mm_load_ps(&this->x());
|
||||
pack_other = _mm_load_ps(&parOther.x());
|
||||
pack_this = _mm_add_ps(pack_this, pack_other);
|
||||
_mm_store_ps(&this->x(), pack_this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
template <typename V2>
|
||||
auto Vec<V, 3, float>::operator-= (const Vec<V2, 3, scalar_type>& parOther) -> Vec& {
|
||||
__m128 pack_this;
|
||||
__m128 pack_other;
|
||||
|
||||
pack_this = _mm_load_ps(&this->x());
|
||||
pack_other = _mm_load_ps(&parOther.x());
|
||||
pack_this = _mm_sub_ps(pack_this, pack_other);
|
||||
_mm_store_ps(&this->x(), pack_this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
inline VecPack<V, 3, float>::VecPack (const Vec<V, 3, float>& parVec) :
|
||||
pack(_mm_load_ps(&parVec.x()))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
inline VecPack<V, 3, float>::VecPack (__m128 parPack) :
|
||||
pack(parPack)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
inline VecPack<V, 3, float>::VecPack (float parValue) :
|
||||
pack(_mm_load1_ps(&parValue))
|
||||
{
|
||||
}
|
||||
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator+ (V1<V, 3, float> parLeft, V2<V, 3, float> parRight) {
|
||||
return _mm_add_ps(VecPack<V, 3, float>(parLeft).pack, VecPack<V, 3, float>(parRight).pack);
|
||||
}
|
||||
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator- (V1<V, 3, float> parLeft, V2<V, 3, float> parRight) {
|
||||
return _mm_sub_ps(VecPack<V, 3, float>(parLeft).pack, VecPack<V, 3, float>(parRight).pack);
|
||||
}
|
||||
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator* (V1<V, 3, float> parLeft, V2<V, 3, float> parRight) {
|
||||
return _mm_mul_ps(VecPack<V, 3, float>(parLeft).pack, VecPack<V, 3, float>(parRight).pack);
|
||||
}
|
||||
|
||||
template <template <typename, std::size_t, typename> class V1, template <typename, std::size_t, typename> class V2, typename V>
|
||||
inline VecPack<V, 3, float> operator/ (V1<V, 3, float> parLeft, V2<V, 3, float> parRight) {
|
||||
return _mm_div_ps(VecPack<V, 3, float>(parLeft).pack, VecPack<V, 3, float>(parRight).pack);
|
||||
}
|
||||
} //namespace simd
|
||||
} //namespace vwr
|
|
@ -1,7 +1,9 @@
|
|||
cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
|
||||
|
||||
include(CTest)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -std=c++11 -g -fno-omit-frame-pointer")
|
||||
|
||||
add_subdirectory(gtest-1.7.0)
|
||||
set(GTEST_MAIN_CPP "${CMAKE_SOURCE_DIR}/gtest-1.7.0/src/gtest_main.cc")
|
||||
|
@ -12,3 +14,4 @@ include_directories(SYSTEM
|
|||
)
|
||||
include_directories(../include)
|
||||
add_subdirectory(unit)
|
||||
add_subdirectory(speed)
|
||||
|
|
18
test/speed/CMakeLists.txt
Normal file
18
test/speed/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
project(speed CXX)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mfpmath=sse -mmmx -msse -msse2")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpmath=sse -mmmx -msse -msse2")
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
${GTEST_MAIN_CPP}
|
||||
speed.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
gtest
|
||||
)
|
||||
add_test(
|
||||
NAME SpeedTest
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND ${PROJECT_NAME}
|
||||
)
|
58
test/speed/speed.cpp
Normal file
58
test/speed/speed.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include "vectorwrapper/vectorops.hpp"
|
||||
#include "vectorwrapper/vectorwrapper_simd.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
namespace vwr {
|
||||
typedef std::aligned_storage<sizeof(float) * 3, 16>::type float3_storage;
|
||||
|
||||
template <>
|
||||
struct VectorWrapperInfo<float3_storage> {
|
||||
enum { dimensions = 3 };
|
||||
typedef float scalar_type;
|
||||
|
||||
enum {
|
||||
offset_x = 0,
|
||||
offset_y = offset_x + sizeof(scalar_type),
|
||||
offset_z = offset_y + sizeof(scalar_type)
|
||||
};
|
||||
};
|
||||
} //namespace vwr
|
||||
|
||||
TEST(vwr_speed, speed) {
|
||||
std::minstd_rand randgen;
|
||||
|
||||
typedef vwr::simd::Vec<vwr::float3_storage> simd_vec3;
|
||||
static_assert(sizeof(simd_vec3) >= sizeof(float) * 3, "SIMD vector too small");
|
||||
|
||||
auto s1 = static_cast<float>(randgen()) / static_cast<float>(randgen.max());
|
||||
auto s2 = static_cast<float>(randgen()) / static_cast<float>(randgen.max());
|
||||
simd_vec3 v1(s1);
|
||||
simd_vec3 v2(s2);
|
||||
|
||||
s1 += s2;
|
||||
v1 += v2;
|
||||
EXPECT_FLOAT_EQ(s1, v1.x());
|
||||
EXPECT_FLOAT_EQ(s1, v1.y());
|
||||
EXPECT_FLOAT_EQ(s1, v1.z());
|
||||
|
||||
auto s3 = s1 + s2;
|
||||
simd_vec3 v3 = v1 + v2;
|
||||
EXPECT_FLOAT_EQ(s3, v3.x());
|
||||
EXPECT_FLOAT_EQ(s3, v3.y());
|
||||
EXPECT_FLOAT_EQ(s3, v3.z());
|
||||
|
||||
auto s4 = (s3 - s2) * s1;
|
||||
simd_vec3 v4 = (v3 - v2) * v1;
|
||||
EXPECT_FLOAT_EQ(s4, v4.x());
|
||||
EXPECT_FLOAT_EQ(s4, v4.y());
|
||||
EXPECT_FLOAT_EQ(s4, v4.z());
|
||||
|
||||
simd_vec3::pack_type zeroeight(0.8f);
|
||||
auto s5 = s4 / s1 + 0.8f;
|
||||
simd_vec3 v5 = v4 / v1 + zeroeight;
|
||||
EXPECT_FLOAT_EQ(s5, v5.x());
|
||||
EXPECT_FLOAT_EQ(s5, v5.y());
|
||||
EXPECT_FLOAT_EQ(s5, v5.z());
|
||||
}
|
|
@ -10,3 +10,9 @@ add_executable(${PROJECT_NAME}
|
|||
target_link_libraries(${PROJECT_NAME}
|
||||
gtest
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME UnitTest
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND ${PROJECT_NAME}
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "vectorwrapper/vectorwrapper.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <ciso646>
|
||||
|
||||
namespace vwr {
|
||||
struct SimpleVector2 {
|
||||
|
@ -185,6 +186,15 @@ namespace vwr {
|
|||
static_assert(sizeof(ivec3) == sizeof(IntVector3), "Wrong size");
|
||||
static_assert(sizeof(mvec3) == sizeof(MixedDataVector3), "Wrong size");
|
||||
static_assert(sizeof(pvec3) == sizeof(PaddedVector3), "Wrong size");
|
||||
static_assert(svec1::is_interleaved_mem == 2, "Maybe interleaved data was expected");
|
||||
static_assert(svec2::is_interleaved_mem == 0, "Non-interleaved data was expected");
|
||||
static_assert(svec3::is_interleaved_mem == 0, "Non-interleaved data was expected");
|
||||
static_assert(ivec1::is_interleaved_mem == 0, "Non-interleaved data was expected");
|
||||
static_assert(ivec2::is_interleaved_mem == 0, "Non-interleaved data was expected");
|
||||
static_assert(ivec3::is_interleaved_mem == 0, "Non-interleaved data was expected");
|
||||
static_assert(mvec3::is_interleaved_mem == 1, "Interleaved data was expected");
|
||||
static_assert(pvec3::is_interleaved_mem == 0, "Interleaved data was expected");
|
||||
static_assert(tvec3::is_interleaved_mem == 0, "Non-interleaved data was expected");
|
||||
|
||||
//Vector Wrapper debug assertions
|
||||
static_assert(not implem::HasOffsetXEnum<VectorWrapperInfo<float>>::value, "Should return false");
|
||||
|
|
Loading…
Reference in a new issue