Vc package added (version 0.6.79-dev)
authorsgorbuno <sgorbuno@f7af4fe6-9843-0410-8265-dc069ae4e863>
Mon, 2 Jul 2012 12:14:49 +0000 (12:14 +0000)
committersgorbuno <sgorbuno@f7af4fe6-9843-0410-8265-dc069ae4e863>
Mon, 2 Jul 2012 12:14:49 +0000 (12:14 +0000)
104 files changed:
Vc/CMakeLists.txt [new file with mode: 0644]
Vc/Vc.cmake [new file with mode: 0644]
Vc/cmake/AddCompilerFlag.cmake [new file with mode: 0644]
Vc/cmake/CheckCCompilerFlag.cmake [new file with mode: 0644]
Vc/cmake/CheckCXXCompilerFlag.cmake [new file with mode: 0644]
Vc/cmake/OptimizeForArchitecture.cmake [new file with mode: 0644]
Vc/cmake/UserWarning.cmake [new file with mode: 0644]
Vc/cmake/VcMacros.cmake [new file with mode: 0644]
Vc/include/Vc/IO [new file with mode: 0644]
Vc/include/Vc/Memory [new file with mode: 0644]
Vc/include/Vc/Utils [new file with mode: 0644]
Vc/include/Vc/Vc [new file with mode: 0644]
Vc/include/Vc/avx/casts.h [new file with mode: 0644]
Vc/include/Vc/avx/const.h [new file with mode: 0644]
Vc/include/Vc/avx/const_data.h [new file with mode: 0644]
Vc/include/Vc/avx/debug.h [new file with mode: 0644]
Vc/include/Vc/avx/deinterleave.tcc [new file with mode: 0644]
Vc/include/Vc/avx/forceToRegisters.tcc [new file with mode: 0644]
Vc/include/Vc/avx/helperimpl.h [new file with mode: 0644]
Vc/include/Vc/avx/helperimpl.tcc [new file with mode: 0644]
Vc/include/Vc/avx/intrinsics.h [new file with mode: 0644]
Vc/include/Vc/avx/limits.h [new file with mode: 0644]
Vc/include/Vc/avx/macros.h [new file with mode: 0644]
Vc/include/Vc/avx/mask.h [new file with mode: 0644]
Vc/include/Vc/avx/mask.tcc [new file with mode: 0644]
Vc/include/Vc/avx/math.h [new file with mode: 0644]
Vc/include/Vc/avx/prefetches.tcc [new file with mode: 0644]
Vc/include/Vc/avx/shuffle.h [new file with mode: 0644]
Vc/include/Vc/avx/sorthelper.h [new file with mode: 0644]
Vc/include/Vc/avx/types.h [new file with mode: 0644]
Vc/include/Vc/avx/undomacros.h [new file with mode: 0644]
Vc/include/Vc/avx/vector.h [new file with mode: 0644]
Vc/include/Vc/avx/vector.tcc [new file with mode: 0644]
Vc/include/Vc/avx/vectorhelper.h [new file with mode: 0644]
Vc/include/Vc/avx/vectorhelper.tcc [new file with mode: 0644]
Vc/include/Vc/avx/writemaskedvector.h [new file with mode: 0644]
Vc/include/Vc/avx/writemaskedvector.tcc [new file with mode: 0644]
Vc/include/Vc/common/aliasingentryhelper.h [new file with mode: 0644]
Vc/include/Vc/common/bitscanintrinsics.h [new file with mode: 0644]
Vc/include/Vc/common/const.h [new file with mode: 0644]
Vc/include/Vc/common/deinterleave.h [new file with mode: 0644]
Vc/include/Vc/common/exponential.h [new file with mode: 0644]
Vc/include/Vc/common/logarithm.h [new file with mode: 0644]
Vc/include/Vc/common/macros.h [new file with mode: 0644]
Vc/include/Vc/common/memory.h [new file with mode: 0644]
Vc/include/Vc/common/memorybase.h [new file with mode: 0644]
Vc/include/Vc/common/memoryfwd.h [new file with mode: 0644]
Vc/include/Vc/common/operators.h [new file with mode: 0644]
Vc/include/Vc/common/storage.h [new file with mode: 0644]
Vc/include/Vc/common/support.h [new file with mode: 0644]
Vc/include/Vc/common/trigonometric.h [new file with mode: 0644]
Vc/include/Vc/common/types.h [new file with mode: 0644]
Vc/include/Vc/common/undomacros.h [new file with mode: 0644]
Vc/include/Vc/common/windows_fix_intrin.h [new file with mode: 0644]
Vc/include/Vc/cpuid.h [new file with mode: 0644]
Vc/include/Vc/double_v [new file with mode: 0644]
Vc/include/Vc/float_v [new file with mode: 0644]
Vc/include/Vc/global.h [new file with mode: 0644]
Vc/include/Vc/int_v [new file with mode: 0644]
Vc/include/Vc/internal/namespace.h [new file with mode: 0644]
Vc/include/Vc/limits [new file with mode: 0644]
Vc/include/Vc/scalar/helperimpl.h [new file with mode: 0644]
Vc/include/Vc/scalar/helperimpl.tcc [new file with mode: 0644]
Vc/include/Vc/scalar/limits.h [new file with mode: 0644]
Vc/include/Vc/scalar/macros.h [new file with mode: 0644]
Vc/include/Vc/scalar/mask.h [new file with mode: 0644]
Vc/include/Vc/scalar/math.h [new file with mode: 0644]
Vc/include/Vc/scalar/types.h [new file with mode: 0644]
Vc/include/Vc/scalar/undomacros.h [new file with mode: 0644]
Vc/include/Vc/scalar/vector.h [new file with mode: 0644]
Vc/include/Vc/scalar/vector.tcc [new file with mode: 0644]
Vc/include/Vc/scalar/writemaskedvector.h [new file with mode: 0644]
Vc/include/Vc/sfloat_v [new file with mode: 0644]
Vc/include/Vc/short_v [new file with mode: 0644]
Vc/include/Vc/sse/casts.h [new file with mode: 0644]
Vc/include/Vc/sse/const.h [new file with mode: 0644]
Vc/include/Vc/sse/const_data.h [new file with mode: 0644]
Vc/include/Vc/sse/debug.h [new file with mode: 0644]
Vc/include/Vc/sse/deinterleave.tcc [new file with mode: 0644]
Vc/include/Vc/sse/forceToRegisters.tcc [new file with mode: 0644]
Vc/include/Vc/sse/helperimpl.h [new file with mode: 0644]
Vc/include/Vc/sse/helperimpl.tcc [new file with mode: 0644]
Vc/include/Vc/sse/intrinsics.h [new file with mode: 0644]
Vc/include/Vc/sse/iterators.h [new file with mode: 0644]
Vc/include/Vc/sse/limits.h [new file with mode: 0644]
Vc/include/Vc/sse/macros.h [new file with mode: 0644]
Vc/include/Vc/sse/mask.h [new file with mode: 0644]
Vc/include/Vc/sse/math.h [new file with mode: 0644]
Vc/include/Vc/sse/prefetches.tcc [new file with mode: 0644]
Vc/include/Vc/sse/shuffle.h [new file with mode: 0644]
Vc/include/Vc/sse/types.h [new file with mode: 0644]
Vc/include/Vc/sse/undomacros.h [new file with mode: 0644]
Vc/include/Vc/sse/vector.h [new file with mode: 0644]
Vc/include/Vc/sse/vector.tcc [new file with mode: 0644]
Vc/include/Vc/sse/vectorhelper.h [new file with mode: 0644]
Vc/include/Vc/sse/vectorhelper.tcc [new file with mode: 0644]
Vc/include/Vc/uint_v [new file with mode: 0644]
Vc/include/Vc/ushort_v [new file with mode: 0644]
Vc/include/Vc/vector.h [new file with mode: 0644]
Vc/include/Vc/version.h [new file with mode: 0644]
Vc/src/avx/sorthelper.cpp [new file with mode: 0644]
Vc/src/cpuid.cpp [new file with mode: 0644]
Vc/src/support.cpp [new file with mode: 0644]
Vc/src/vector.cpp [new file with mode: 0644]

diff --git a/Vc/CMakeLists.txt b/Vc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..62de54d
--- /dev/null
@@ -0,0 +1,37 @@
+macro(vc_add_target_property _target _prop _value)
+   get_target_property(_oldprop "${_target}" ${_prop})
+   if(NOT _oldprop)
+      set_target_properties("${_target}" PROPERTIES ${_prop} "${_value}")
+   else(NOT _oldprop)
+      set_target_properties("${_target}" PROPERTIES ${_prop} "${_oldprop} ${_value}")
+   endif(NOT _oldprop)
+endmacro()
+
+include_directories("${Vc_INCLUDE_DIR}" "${Vc_INCLUDE_DIR}/Vc" "${Vc_INCLUDE_DIR}/Vc/avx")
+
+if(USE_AVX)
+   add_library(Vc STATIC src/vector.cpp src/cpuid.cpp src/support.cpp src/avx/sorthelper.cpp)
+else()
+   set(_srcs src/vector.cpp src/cpuid.cpp src/support.cpp)
+
+   if(NOT Vc_AVX_INTRINSICS_BROKEN)
+      # we'd still like to have avx/sorthelper.cpp built in, but that requires compilation with -mavx (or a comparable flag)
+      foreach(_flag "-xAVX" "-mavx" "-arch:AVX")
+         check_cxx_compiler_flag("${_flag}" check_cxx_compiler_flag_${_flag})
+         if(check_cxx_compiler_flag_${_flag})
+            if(_flag STREQUAL "-xAVX")
+               set(_flag "${_flag} -diag-disable 10121") # disable the warning "overriding -xSSE4.2 with -xAVX"
+            endif()
+            set(_srcs ${_srcs} src/avx/sorthelper.cpp)
+            set_source_files_properties(src/avx/sorthelper.cpp PROPERTIES COMPILE_FLAGS "${_flag}")
+            break()
+         endif()
+      endforeach()
+   endif()
+   add_library(Vc STATIC ${_srcs})
+endif()
+string(REPLACE "-Weffc++" "" CXXFLAGS "${CXXFLAGS}")
+vc_add_target_property(Vc COMPILE_FLAGS "-DVC_COMPILE_LIB ${CXXFLAGS} -O3 ${Vc_DEFINITIONS}")
+vc_add_target_property(Vc LABELS "other")
+
+# vim: ft=cmake sw=3 et
diff --git a/Vc/Vc.cmake b/Vc/Vc.cmake
new file mode 100644 (file)
index 0000000..8d0580f
--- /dev/null
@@ -0,0 +1,11 @@
+set(Vc_INCLUDE_DIR          "${PROJECT_SOURCE_DIR}/Vc/include")
+set(Vc_CMAKE_MODULES_DIR    "${PROJECT_SOURCE_DIR}/Vc/cmake")
+include("${Vc_CMAKE_MODULES_DIR}/VcMacros.cmake")
+vc_set_preferred_compiler_flags()
+
+macro(ALICE_UseVc)
+   include_directories(SYSTEM "${Vc_INCLUDE_DIR}")
+   add_definitions(${Vc_DEFINITIONS})
+endmacro()
+
+# vim: ft=cmake sw=3 et
diff --git a/Vc/cmake/AddCompilerFlag.cmake b/Vc/cmake/AddCompilerFlag.cmake
new file mode 100644 (file)
index 0000000..30eb7e8
--- /dev/null
@@ -0,0 +1,46 @@
+get_filename_component(_currentDir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include("${_currentDir}/CheckCCompilerFlag.cmake")
+include("${_currentDir}/CheckCXXCompilerFlag.cmake")
+macro(AddCompilerFlag _flag)
+   string(REGEX REPLACE "[-+/:= ]" "_" _flag_esc "${_flag}")
+   check_c_compiler_flag("${_flag}" check_c_compiler_flag_${_flag_esc})
+   check_cxx_compiler_flag("${_flag}" check_cxx_compiler_flag_${_flag_esc})
+
+   set(_c_flags "CMAKE_C_FLAGS")
+   set(_cxx_flags "CMAKE_CXX_FLAGS")
+   if(${ARGC} EQUAL 2)
+      set(${ARGV1} "${check_cxx_compiler_flag_${_flag_esc}}")
+   elseif(${ARGC} GREATER 2)
+      set(state 0)
+      unset(_c_flags)
+      unset(_cxx_flags)
+      foreach(_arg ${ARGN})
+         if(_arg STREQUAL "C_FLAGS")
+            set(state 1)
+         elseif(_arg STREQUAL "CXX_FLAGS")
+            set(state 2)
+         elseif(_arg STREQUAL "C_RESULT")
+            set(state 3)
+         elseif(_arg STREQUAL "CXX_RESULT")
+            set(state 4)
+         elseif(state EQUAL 1)
+            set(_c_flags "${_arg}")
+         elseif(state EQUAL 2)
+            set(_cxx_flags "${_arg}")
+         elseif(state EQUAL 3)
+            set(${_arg} ${check_c_compiler_flag_${_flag_esc}})
+         elseif(state EQUAL 4)
+            set(${_arg} ${check_cxx_compiler_flag_${_flag_esc}})
+         else()
+            message(FATAL_ERROR "Syntax error for AddCompilerFlag")
+         endif()
+      endforeach()
+   endif()
+
+   if(check_c_compiler_flag_${_flag_esc} AND DEFINED _c_flags)
+      set(${_c_flags} "${${_c_flags}} ${_flag}")
+   endif()
+   if(check_cxx_compiler_flag_${_flag_esc} AND DEFINED _cxx_flags)
+      set(${_cxx_flags} "${${_cxx_flags}} ${_flag}")
+   endif()
+endmacro(AddCompilerFlag)
diff --git a/Vc/cmake/CheckCCompilerFlag.cmake b/Vc/cmake/CheckCCompilerFlag.cmake
new file mode 100644 (file)
index 0000000..3c904dd
--- /dev/null
@@ -0,0 +1,43 @@
+# - Check whether the C compiler supports a given flag.
+# CHECK_C_COMPILER_FLAG(<flag> <var>)
+#  <flag> - the compiler flag
+#  <var>  - variable to store the result
+# This internally calls the check_c_source_compiles macro.
+# See help for CheckCSourceCompiles for a listing of variables
+# that can modify the build.
+
+#=============================================================================
+# Copyright 2006-2009 Kitware, Inc.
+# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
+# Copyright 2011 Matthias Kretz <kretz@kde.org>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+INCLUDE(CheckCSourceCompiles)
+
+MACRO (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
+   SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+   SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+   CHECK_C_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT}
+     # Some compilers do not fail with a bad flag
+     FAIL_REGEX "argument unused during compilation"        # clang
+     FAIL_REGEX "is valid for .* but not for C"             # GNU
+     FAIL_REGEX "unrecognized .*option"                     # GNU
+     FAIL_REGEX "ignoring unknown option"                   # MSVC
+     FAIL_REGEX "[Uu]nknown option"                         # HP
+     FAIL_REGEX "[Ww]arning: [Oo]ption"                     # SunPro
+     FAIL_REGEX "command option .* is not recognized"       # XL
+     FAIL_REGEX "WARNING: unknown flag:"                    # Open64
+     FAIL_REGEX " #10159: "                                 # ICC
+     )
+   SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ENDMACRO (CHECK_C_COMPILER_FLAG)
+
diff --git a/Vc/cmake/CheckCXXCompilerFlag.cmake b/Vc/cmake/CheckCXXCompilerFlag.cmake
new file mode 100644 (file)
index 0000000..fccc97b
--- /dev/null
@@ -0,0 +1,43 @@
+# - Check whether the CXX compiler supports a given flag.
+# CHECK_CXX_COMPILER_FLAG(<flag> <var>)
+#  <flag> - the compiler flag
+#  <var>  - variable to store the result
+# This internally calls the check_cxx_source_compiles macro.  See help
+# for CheckCXXSourceCompiles for a listing of variables that can
+# modify the build.
+
+#=============================================================================
+# Copyright 2006-2009 Kitware, Inc.
+# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
+# Copyright 2011 Matthias Kretz <kretz@kde.org>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+INCLUDE(CheckCXXSourceCompiles)
+
+MACRO (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+   SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+   SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+   CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT}
+     # Some compilers do not fail with a bad flag
+     FAIL_REGEX "argument unused during compilation"        # clang
+     FAIL_REGEX "is valid for .* but not for C\\\\+\\\\+"   # GNU
+     FAIL_REGEX "unrecognized .*option"                     # GNU
+     FAIL_REGEX "ignoring unknown option"                   # MSVC
+     FAIL_REGEX "[Uu]nknown option"                         # HP
+     FAIL_REGEX "[Ww]arning: [Oo]ption"                     # SunPro
+     FAIL_REGEX "command option .* is not recognized"       # XL
+     FAIL_REGEX "WARNING: unknown flag:"                    # Open64
+     FAIL_REGEX " #10159: "                                 # ICC
+     )
+   SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ENDMACRO (CHECK_CXX_COMPILER_FLAG)
+
diff --git a/Vc/cmake/OptimizeForArchitecture.cmake b/Vc/cmake/OptimizeForArchitecture.cmake
new file mode 100644 (file)
index 0000000..01f435c
--- /dev/null
@@ -0,0 +1,339 @@
+get_filename_component(_currentDir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include("${_currentDir}/AddCompilerFlag.cmake")
+
+macro(_my_find _list _value _ret)
+   list(FIND ${_list} "${_value}" _found)
+   if(_found EQUAL -1)
+      set(${_ret} FALSE)
+   else(_found EQUAL -1)
+      set(${_ret} TRUE)
+   endif(_found EQUAL -1)
+endmacro(_my_find)
+
+macro(AutodetectHostArchitecture)
+   set(TARGET_ARCHITECTURE "generic")
+   set(Vc_ARCHITECTURE_FLAGS)
+   set(_vendor_id)
+   set(_cpu_family)
+   set(_cpu_model)
+   if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+      file(READ "/proc/cpuinfo" _cpuinfo)
+      string(REGEX REPLACE ".*vendor_id[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _vendor_id "${_cpuinfo}")
+      string(REGEX REPLACE ".*cpu family[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_family "${_cpuinfo}")
+      string(REGEX REPLACE ".*model[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_model "${_cpuinfo}")
+      string(REGEX REPLACE ".*flags[ \t]*:[ \t]+([a-zA-Z0-9_-]+).*" "\\1" _cpu_flags "${_cpuinfo}")
+   elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+      exec_program("/usr/sbin/sysctl -n machdep.cpu.vendor" OUTPUT_VARIABLE _vendor_id)
+      exec_program("/usr/sbin/sysctl -n machdep.cpu.model"  OUTPUT_VARIABLE _cpu_model)
+      exec_program("/usr/sbin/sysctl -n machdep.cpu.family" OUTPUT_VARIABLE _cpu_family)
+      exec_program("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE _cpu_flags)
+      string(TOLOWER "${_cpu_flags}" _cpu_flags)
+      string(REPLACE "." "_" _cpu_flags "${_cpu_flags}")
+   elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+      get_filename_component(_vendor_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;VendorIdentifier]" NAME CACHE)
+      get_filename_component(_cpu_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;Identifier]" NAME CACHE)
+      mark_as_advanced(_vendor_id _cpu_id)
+      string(REGEX REPLACE ".* Family ([0-9]+) .*" "\\1" _cpu_family "${_cpu_id}")
+      string(REGEX REPLACE ".* Model ([0-9]+) .*" "\\1" _cpu_model "${_cpu_id}")
+   endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+   if(_vendor_id STREQUAL "GenuineIntel")
+      if(_cpu_family EQUAL 6)
+         # Any recent Intel CPU except NetBurst
+         if(_cpu_model EQUAL 46)     # Xeon 7500 series
+            set(TARGET_ARCHITECTURE "westmere")
+         elseif(_cpu_model EQUAL 45) # Xeon TNG
+            set(TARGET_ARCHITECTURE "sandy-bridge")
+         elseif(_cpu_model EQUAL 44) # Xeon 5600 series
+            set(TARGET_ARCHITECTURE "westmere")
+         elseif(_cpu_model EQUAL 42) # Core TNG
+            set(TARGET_ARCHITECTURE "sandy-bridge")
+         elseif(_cpu_model EQUAL 37) # Core i7/i5/i3
+            set(TARGET_ARCHITECTURE "westmere")
+         elseif(_cpu_model EQUAL 31) # Core i7/i5
+            set(TARGET_ARCHITECTURE "westmere")
+         elseif(_cpu_model EQUAL 30) # Core i7/i5
+            set(TARGET_ARCHITECTURE "westmere")
+         elseif(_cpu_model EQUAL 29)
+            set(TARGET_ARCHITECTURE "penryn")
+         elseif(_cpu_model EQUAL 28)
+            set(TARGET_ARCHITECTURE "atom")
+         elseif(_cpu_model EQUAL 26)
+            set(TARGET_ARCHITECTURE "nehalem")
+         elseif(_cpu_model EQUAL 23)
+            set(TARGET_ARCHITECTURE "penryn")
+         elseif(_cpu_model EQUAL 15)
+            set(TARGET_ARCHITECTURE "merom")
+         elseif(_cpu_model EQUAL 14)
+            set(TARGET_ARCHITECTURE "core")
+         elseif(_cpu_model LESS 14)
+            message(WARNING "Your CPU (family ${_cpu_family}, model ${_cpu_model}) is not known. Auto-detection of optimization flags failed and will use the generic CPU settings with SSE2.")
+            set(TARGET_ARCHITECTURE "generic")
+         else()
+            message(WARNING "Your CPU (family ${_cpu_family}, model ${_cpu_model}) is not known. Auto-detection of optimization flags failed and will use the 65nm Core 2 CPU settings.")
+            set(TARGET_ARCHITECTURE "merom")
+         endif()
+      elseif(_cpu_family EQUAL 7) # Itanium (not supported)
+         message(WARNING "Your CPU (Itanium: family ${_cpu_family}, model ${_cpu_model}) is not supported by OptimizeForArchitecture.cmake.")
+      elseif(_cpu_family EQUAL 15) # NetBurst
+         list(APPEND _available_vector_units_list "sse" "sse2")
+         if(_cpu_model GREATER 2) # Not sure whether this must be 3 or even 4 instead
+            list(APPEND _available_vector_units_list "sse" "sse2" "sse3")
+         endif(_cpu_model GREATER 2)
+      endif(_cpu_family EQUAL 6)
+   elseif(_vendor_id STREQUAL "AuthenticAMD")
+      if(_cpu_family EQUAL 21) # 15h
+         set(TARGET_ARCHITECTURE "bulldozer")
+      elseif(_cpu_family EQUAL 20) # 14h
+      elseif(_cpu_family EQUAL 18) # 12h
+      elseif(_cpu_family EQUAL 16) # 10h
+         set(TARGET_ARCHITECTURE "barcelona")
+      elseif(_cpu_family EQUAL 15)
+         set(TARGET_ARCHITECTURE "k8")
+         if(_cpu_model GREATER 64) # I don't know the right number to put here. This is just a guess from the hardware I have access to
+            set(TARGET_ARCHITECTURE "k8-sse3")
+         endif(_cpu_model GREATER 64)
+      endif()
+   endif(_vendor_id STREQUAL "GenuineIntel")
+endmacro()
+
+macro(OptimizeForArchitecture)
+   set(TARGET_ARCHITECTURE "auto" CACHE STRING "CPU architecture to optimize for. Using an incorrect setting here can result in crashes of the resulting binary because of invalid instructions used.\nSetting the value to \"auto\" will try to optimize for the architecture where cmake is called.\nOther supported values are: \"generic\", \"core\", \"merom\" (65nm Core2), \"penryn\" (45nm Core2), \"nehalem\", \"westmere\", \"sandy-bridge\", \"atom\", \"k8\", \"k8-sse3\", \"barcelona\", \"istanbul\", \"magny-cours\", \"bulldozer\", \"interlagos\".")
+   set(_force)
+   if(NOT _last_target_arch STREQUAL "${TARGET_ARCHITECTURE}")
+      message(STATUS "target changed from \"${_last_target_arch}\" to \"${TARGET_ARCHITECTURE}\"")
+      set(_force FORCE)
+   endif()
+   set(_last_target_arch "${TARGET_ARCHITECTURE}" CACHE STRING "" FORCE)
+   mark_as_advanced(_last_target_arch)
+   string(TOLOWER "${TARGET_ARCHITECTURE}" TARGET_ARCHITECTURE)
+
+   set(_march_flag_list)
+   set(_available_vector_units_list)
+
+   if(TARGET_ARCHITECTURE STREQUAL "auto")
+      AutodetectHostArchitecture()
+      message(STATUS "Detected CPU: ${TARGET_ARCHITECTURE}")
+   endif(TARGET_ARCHITECTURE STREQUAL "auto")
+
+   if(TARGET_ARCHITECTURE STREQUAL "core")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3")
+   elseif(TARGET_ARCHITECTURE STREQUAL "merom")
+      list(APPEND _march_flag_list "merom")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
+   elseif(TARGET_ARCHITECTURE STREQUAL "penryn")
+      list(APPEND _march_flag_list "penryn")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
+      message(STATUS "Sadly the Penryn architecture exists in variants with SSE4.1 and without SSE4.1.")
+      if(_cpu_flags MATCHES "sse4_1")
+         message(STATUS "SSE4.1: enabled (auto-detected from this computer's CPU flags)")
+         list(APPEND _available_vector_units_list "sse4.1")
+      else()
+         message(STATUS "SSE4.1: disabled (auto-detected from this computer's CPU flags)")
+      endif()
+   elseif(TARGET_ARCHITECTURE STREQUAL "nehalem")
+      list(APPEND _march_flag_list "nehalem")
+      list(APPEND _march_flag_list "corei7")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4.1" "sse4.2")
+   elseif(TARGET_ARCHITECTURE STREQUAL "westmere")
+      list(APPEND _march_flag_list "westmere")
+      list(APPEND _march_flag_list "corei7")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4.1" "sse4.2")
+   elseif(TARGET_ARCHITECTURE STREQUAL "sandy-bridge")
+      list(APPEND _march_flag_list "sandybridge")
+      list(APPEND _march_flag_list "corei7-avx")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4.1" "sse4.2" "avx")
+   elseif(TARGET_ARCHITECTURE STREQUAL "atom")
+      list(APPEND _march_flag_list "atom")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3")
+   elseif(TARGET_ARCHITECTURE STREQUAL "k8")
+      list(APPEND _march_flag_list "k8")
+      list(APPEND _available_vector_units_list "sse" "sse2")
+   elseif(TARGET_ARCHITECTURE STREQUAL "k8-sse3")
+      list(APPEND _march_flag_list "k8-sse3")
+      list(APPEND _march_flag_list "k8")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3")
+   elseif(TARGET_ARCHITECTURE STREQUAL "interlagos")
+      list(APPEND _march_flag_list "bulldozer")
+      list(APPEND _march_flag_list "barcelona")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "xop" "fma4")
+   elseif(TARGET_ARCHITECTURE STREQUAL "bulldozer")
+      list(APPEND _march_flag_list "bulldozer")
+      list(APPEND _march_flag_list "barcelona")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "ssse3" "sse4a" "sse4.1" "sse4.2" "avx" "xop" "fma4")
+   elseif(TARGET_ARCHITECTURE STREQUAL "barcelona")
+      list(APPEND _march_flag_list "barcelona")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "sse4a")
+   elseif(TARGET_ARCHITECTURE STREQUAL "istanbul")
+      list(APPEND _march_flag_list "barcelona")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "sse4a")
+   elseif(TARGET_ARCHITECTURE STREQUAL "magny-cours")
+      list(APPEND _march_flag_list "barcelona")
+      list(APPEND _march_flag_list "core2")
+      list(APPEND _available_vector_units_list "sse" "sse2" "sse3" "sse4a")
+   elseif(TARGET_ARCHITECTURE STREQUAL "generic")
+      list(APPEND _march_flag_list "generic")
+   else(TARGET_ARCHITECTURE STREQUAL "core")
+      message(FATAL_ERROR "Unknown target architecture: \"${TARGET_ARCHITECTURE}\". Please set TARGET_ARCHITECTURE to a supported value.")
+   endif(TARGET_ARCHITECTURE STREQUAL "core")
+
+   set(_disable_vector_unit_list)
+   set(_enable_vector_unit_list)
+   _my_find(_available_vector_units_list "sse2" SSE2_FOUND)
+   _my_find(_available_vector_units_list "sse3" SSE3_FOUND)
+   _my_find(_available_vector_units_list "ssse3" SSSE3_FOUND)
+   _my_find(_available_vector_units_list "sse4.1" SSE4_1_FOUND)
+   _my_find(_available_vector_units_list "sse4.2" SSE4_2_FOUND)
+   _my_find(_available_vector_units_list "sse4a" SSE4a_FOUND)
+   if(DEFINED Vc_AVX_INTRINSICS_BROKEN AND Vc_AVX_INTRINSICS_BROKEN)
+      UserWarning("AVX disabled per default because of old/broken compiler")
+      set(AVX_FOUND false)
+      set(XOP_FOUND false)
+      set(FMA4_FOUND false)
+   else()
+      _my_find(_available_vector_units_list "avx" AVX_FOUND)
+      _my_find(_available_vector_units_list "xop" XOP_FOUND)
+      _my_find(_available_vector_units_list "fma4" FMA4_FOUND)
+   endif()
+   set(USE_SSE2   ${SSE2_FOUND}   CACHE BOOL "Use SSE2. If SSE2 instructions are not enabled the SSE implementation will be disabled." ${_force})
+   set(USE_SSE3   ${SSE3_FOUND}   CACHE BOOL "Use SSE3. If SSE3 instructions are not enabled they will be emulated." ${_force})
+   set(USE_SSSE3  ${SSSE3_FOUND}  CACHE BOOL "Use SSSE3. If SSSE3 instructions are not enabled they will be emulated." ${_force})
+   set(USE_SSE4_1 ${SSE4_1_FOUND} CACHE BOOL "Use SSE4.1. If SSE4.1 instructions are not enabled they will be emulated." ${_force})
+   set(USE_SSE4_2 ${SSE4_2_FOUND} CACHE BOOL "Use SSE4.2. If SSE4.2 instructions are not enabled they will be emulated." ${_force})
+   set(USE_SSE4a  ${SSE4a_FOUND}  CACHE BOOL "Use SSE4a. If SSE4a instructions are not enabled they will be emulated." ${_force})
+   set(USE_AVX    ${AVX_FOUND}    CACHE BOOL "Use AVX. This will double some of the vector sizes relative to SSE." ${_force})
+   set(USE_XOP    ${XOP_FOUND}    CACHE BOOL "Use XOP." ${_force})
+   set(USE_FMA4   ${FMA4_FOUND}   CACHE BOOL "Use FMA4." ${_force})
+   mark_as_advanced(USE_SSE2 USE_SSE3 USE_SSSE3 USE_SSE4_1 USE_SSE4_2 USE_SSE4a USE_AVX USE_XOP USE_FMA4)
+   if(USE_SSE2)
+      list(APPEND _enable_vector_unit_list "sse2")
+   else(USE_SSE2)
+      list(APPEND _disable_vector_unit_list "sse2")
+   endif(USE_SSE2)
+   if(USE_SSE3)
+      list(APPEND _enable_vector_unit_list "sse3")
+   else(USE_SSE3)
+      list(APPEND _disable_vector_unit_list "sse3")
+   endif(USE_SSE3)
+   if(USE_SSSE3)
+      list(APPEND _enable_vector_unit_list "ssse3")
+   else(USE_SSSE3)
+      list(APPEND _disable_vector_unit_list "ssse3")
+   endif(USE_SSSE3)
+   if(USE_SSE4_1)
+      list(APPEND _enable_vector_unit_list "sse4.1")
+   else(USE_SSE4_1)
+      list(APPEND _disable_vector_unit_list "sse4.1")
+   endif(USE_SSE4_1)
+   if(USE_SSE4_2)
+      list(APPEND _enable_vector_unit_list "sse4.2")
+   else(USE_SSE4_2)
+      list(APPEND _disable_vector_unit_list "sse4.2")
+   endif(USE_SSE4_2)
+   if(USE_SSE4a)
+      list(APPEND _enable_vector_unit_list "sse4a")
+   else(USE_SSE4a)
+      list(APPEND _disable_vector_unit_list "sse4a")
+   endif(USE_SSE4a)
+   if(USE_AVX)
+      list(APPEND _enable_vector_unit_list "avx")
+      # we want SSE intrinsics to result in instructions using the VEX prefix.
+      # Otherwise integer ops (which require the older SSE intrinsics) would
+      # always have a large penalty.
+      list(APPEND _enable_vector_unit_list "sse2avx")
+   else(USE_AVX)
+      list(APPEND _disable_vector_unit_list "avx")
+   endif(USE_AVX)
+   if(USE_XOP)
+      list(APPEND _enable_vector_unit_list "xop")
+   else()
+      list(APPEND _disable_vector_unit_list "xop")
+   endif()
+   if(USE_FMA4)
+      list(APPEND _enable_vector_unit_list "fma4")
+   else()
+      list(APPEND _disable_vector_unit_list "fma4")
+   endif()
+   if(MSVC)
+      # MSVC on 32 bit can select /arch:SSE2 (since 2010 also /arch:AVX)
+      # MSVC on 64 bit cannot select anything (should have changed with MSVC 2010)
+      _my_find(_enable_vector_unit_list "avx" _avx)
+      set(_avx_flag FALSE)
+      if(_avx)
+         AddCompilerFlag("/arch:AVX" CXX_FLAGS Vc_ARCHITECTURE_FLAGS CXX_RESULT _avx_flag)
+      endif()
+      if(NOT _avx_flag)
+         _my_find(_enable_vector_unit_list "sse2" _found)
+         if(_found)
+            AddCompilerFlag("/arch:SSE2" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+         endif()
+      endif()
+      foreach(_flag ${_enable_vector_unit_list})
+         string(TOUPPER "${_flag}" _flag)
+         string(REPLACE "." "_" _flag "__${_flag}__")
+         add_definitions("-D${_flag}")
+      endforeach(_flag)
+   elseif(CMAKE_CXX_COMPILER MATCHES "/(icpc|icc)$") # ICC (on Linux)
+      _my_find(_available_vector_units_list "avx"    _found)
+      if(_found)
+         AddCompilerFlag("-xAVX" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+      else(_found)
+         _my_find(_available_vector_units_list "sse4.2" _found)
+         if(_found)
+            AddCompilerFlag("-xSSE4.2" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+         else(_found)
+            _my_find(_available_vector_units_list "sse4.1" _found)
+            if(_found)
+               AddCompilerFlag("-xSSE4.1" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+            else(_found)
+               _my_find(_available_vector_units_list "ssse3"  _found)
+               if(_found)
+                  AddCompilerFlag("-xSSSE3" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+               else(_found)
+                  _my_find(_available_vector_units_list "sse3"   _found)
+                  if(_found)
+                     # If the target host is an AMD machine then we still want to use -xSSE2 because the binary would refuse to run at all otherwise
+                     _my_find(_march_flag_list "barcelona" _found)
+                     if(NOT _found)
+                        _my_find(_march_flag_list "k8-sse3" _found)
+                     endif(NOT _found)
+                     if(_found)
+                        AddCompilerFlag("-xSSE2" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+                     else(_found)
+                        AddCompilerFlag("-xSSE3" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+                     endif(_found)
+                  else(_found)
+                     _my_find(_available_vector_units_list "sse2"   _found)
+                     if(_found)
+                        AddCompilerFlag("-xSSE2" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+                     endif(_found)
+                  endif(_found)
+               endif(_found)
+            endif(_found)
+         endif(_found)
+      endif(_found)
+   else() # not MSVC and not ICC => GCC, Clang, Open64
+      foreach(_flag ${_march_flag_list})
+         AddCompilerFlag("-march=${_flag}" CXX_RESULT _good CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+         if(_good)
+            break()
+         endif(_good)
+      endforeach(_flag)
+      foreach(_flag ${_enable_vector_unit_list})
+         AddCompilerFlag("-m${_flag}" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+      endforeach(_flag)
+      foreach(_flag ${_disable_vector_unit_list})
+         AddCompilerFlag("-mno-${_flag}" CXX_FLAGS Vc_ARCHITECTURE_FLAGS)
+      endforeach(_flag)
+   endif()
+endmacro(OptimizeForArchitecture)
diff --git a/Vc/cmake/UserWarning.cmake b/Vc/cmake/UserWarning.cmake
new file mode 100644 (file)
index 0000000..0be6ad2
--- /dev/null
@@ -0,0 +1,9 @@
+macro(UserWarning _msg)
+   if("$ENV{DASHBOARD_TEST_FROM_CTEST}" STREQUAL "")
+      # developer (non-dashboard) build
+      message(WARNING "${_msg}")
+   else()
+      # dashboard build
+      message(STATUS "${_msg}")
+   endif()
+endmacro()
diff --git a/Vc/cmake/VcMacros.cmake b/Vc/cmake/VcMacros.cmake
new file mode 100644 (file)
index 0000000..f5956f4
--- /dev/null
@@ -0,0 +1,305 @@
+# Macros for use with the Vc library. Vc can be found at http://code.compeng.uni-frankfurt.de/projects/vc
+#
+# The following macros are provided:
+# vc_determine_compiler
+# vc_set_preferred_compiler_flags
+#
+#=============================================================================
+# Copyright 2009-2012   Matthias Kretz <kretz@kde.org>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file CmakeCopyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+get_filename_component(_currentDir "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include ("${_currentDir}/UserWarning.cmake")
+include ("${_currentDir}/AddCompilerFlag.cmake")
+include ("${_currentDir}/OptimizeForArchitecture.cmake")
+
+macro(vc_determine_compiler)
+   if(NOT DEFINED Vc_COMPILER_IS_INTEL)
+      set(Vc_COMPILER_IS_INTEL false)
+      set(Vc_COMPILER_IS_OPEN64 false)
+      set(Vc_COMPILER_IS_CLANG false)
+      set(Vc_COMPILER_IS_MSVC false)
+      set(Vc_COMPILER_IS_GCC false)
+      if(CMAKE_CXX_COMPILER MATCHES "/(icpc|icc)$")
+         set(Vc_COMPILER_IS_INTEL true)
+         exec_program(${CMAKE_C_COMPILER} ARGS -dumpversion OUTPUT_VARIABLE Vc_ICC_VERSION)
+         message(STATUS "Detected Compiler: Intel ${Vc_ICC_VERSION}")
+      elseif(CMAKE_CXX_COMPILER MATCHES "/(opencc|openCC)$")
+         set(Vc_COMPILER_IS_OPEN64 true)
+         message(STATUS "Detected Compiler: Open64")
+      elseif(CMAKE_CXX_COMPILER MATCHES "/clang\\+\\+$")
+         set(Vc_COMPILER_IS_CLANG true)
+         message(STATUS "Detected Compiler: Clang")
+      elseif(MSVC)
+         set(Vc_COMPILER_IS_MSVC true)
+         message(STATUS "Detected Compiler: MSVC")
+      elseif(CMAKE_COMPILER_IS_GNUCXX)
+         set(Vc_COMPILER_IS_GCC true)
+         exec_program(${CMAKE_C_COMPILER} ARGS -dumpversion OUTPUT_VARIABLE Vc_GCC_VERSION)
+         message(STATUS "Detected Compiler: GCC ${Vc_GCC_VERSION}")
+
+         # some distributions patch their GCC to return nothing or only major and minor version on -dumpversion.
+         # In that case we must extract the version number from --version.
+         if(NOT Vc_GCC_VERSION OR Vc_GCC_VERSION MATCHES "^[0-9]\\.[0-9]+$")
+            exec_program(${CMAKE_C_COMPILER} ARGS --version OUTPUT_VARIABLE Vc_GCC_VERSION)
+            string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" Vc_GCC_VERSION "${Vc_GCC_VERSION}")
+            message(STATUS "GCC Version from --version: ${Vc_GCC_VERSION}")
+         endif()
+
+         # some distributions patch their GCC to be API incompatible to what the FSF released. In
+         # those cases we require a macro to identify the distribution version
+         find_program(_lsb_release lsb_release)
+         mark_as_advanced(_lsb_release)
+         if(_lsb_release)
+            execute_process(COMMAND ${_lsb_release} -is OUTPUT_VARIABLE _distributor_id OUTPUT_STRIP_TRAILING_WHITESPACE)
+            execute_process(COMMAND ${_lsb_release} -rs OUTPUT_VARIABLE _distributor_release OUTPUT_STRIP_TRAILING_WHITESPACE)
+            string(TOUPPER "${_distributor_id}" _distributor_id)
+            if(_distributor_id STREQUAL "UBUNTU")
+               execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE _gcc_version)
+               string(REGEX MATCH "\\(.* ${Vc_GCC_VERSION}-([0-9]+).*\\)" _tmp "${_gcc_version}")
+               if(_tmp)
+                  set(_patch ${CMAKE_MATCH_1})
+                  string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _tmp "${_distributor_release}")
+                  execute_process(COMMAND printf 0x%x%02x%02x ${CMAKE_MATCH_1} ${CMAKE_MATCH_2} ${_patch} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE _tmp)
+                  set(Vc_DEFINITIONS "${Vc_DEFINITIONS} -D__GNUC_UBUNTU_VERSION__=${_tmp}")
+               endif()
+            endif()
+         endif()
+      else()
+         message(WARNING "Untested/-supported Compiler for use with Vc.\nPlease fill out the missing parts in the CMake scripts and submit a patch to http://code.compeng.uni-frankfurt.de/projects/vc")
+      endif()
+   endif()
+endmacro()
+
+macro(vc_set_gnu_buildtype_flags)
+   set(CMAKE_CXX_FLAGS_DEBUG          "-g3"          CACHE STRING "Flags used by the compiler during debug builds." FORCE)
+   set(CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG" CACHE STRING "Flags used by the compiler during release minsize builds." FORCE)
+   set(CMAKE_CXX_FLAGS_RELEASE        "-O3 -DNDEBUG" CACHE STRING "Flags used by the compiler during release builds (/MD /Ob1 /Oi /Ot /Oy /Gs will produce slightly less optimized but smaller files)." FORCE)
+   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -g" CACHE STRING "Flags used by the compiler during Release with Debug Info builds." FORCE)
+   set(CMAKE_C_FLAGS_DEBUG          "${CMAKE_CXX_FLAGS_DEBUG}"          CACHE STRING "Flags used by the compiler during debug builds." FORCE)
+   set(CMAKE_C_FLAGS_MINSIZEREL     "${CMAKE_CXX_FLAGS_MINSIZEREL}"     CACHE STRING "Flags used by the compiler during release minsize builds." FORCE)
+   set(CMAKE_C_FLAGS_RELEASE        "${CMAKE_CXX_FLAGS_RELEASE}"        CACHE STRING "Flags used by the compiler during release builds (/MD /Ob1 /Oi /Ot /Oy /Gs will produce slightly less optimized but smaller files)." FORCE)
+   set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the compiler during Release with Debug Info builds." FORCE)
+   if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+      set(ENABLE_STRICT_ALIASING true CACHE BOOL "Enables strict aliasing rules for more aggressive optimizations")
+      if(NOT ENABLE_STRICT_ALIASING)
+         set(CMAKE_CXX_FLAGS_RELEASE        "${CMAKE_CXX_FLAGS_RELEASE} -fno-strict-aliasing ")
+         set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-strict-aliasing ")
+         set(CMAKE_C_FLAGS_RELEASE        "${CMAKE_C_FLAGS_RELEASE} -fno-strict-aliasing ")
+         set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fno-strict-aliasing ")
+      endif(NOT ENABLE_STRICT_ALIASING)
+   endif()
+endmacro()
+
+macro(vc_add_compiler_flag VAR _flag)
+   AddCompilerFlag("${_flag}" CXX_FLAGS ${VAR})
+endmacro()
+
+macro(vc_check_assembler)
+   if(APPLE)
+      if(NOT Vc_COMPILER_IS_CLANG)
+         message(WARNING "Apple does not provide an assembler with AVX support. Please use Clang instead of GCC.")
+      endif()
+   else(APPLE)
+      if(${ARGC} EQUAL 1)
+         set(_as "${ARGV1}")
+      else()
+         exec_program(${CMAKE_CXX_COMPILER} ARGS -print-prog-name=as OUTPUT_VARIABLE _as)
+         mark_as_advanced(_as)
+      endif()
+      if(NOT _as)
+         message(WARNING "Could not find 'as', the assembler used by GCC. Hoping everything will work out...")
+      else()
+         exec_program(${_as} ARGS --version OUTPUT_VARIABLE _as_version)
+         string(REGEX REPLACE "\\([^\\)]*\\)" "" _as_version "${_as_version}")
+         string(REGEX MATCH "[1-9]\\.[0-9]+(\\.[0-9]+)?" _as_version "${_as_version}")
+         if(_as_version VERSION_LESS "2.18.93")
+            message(WARNING "Your binutils is too old (${_as_version}). Some optimizations of Vc will be disabled.")
+            add_definitions(-DVC_NO_XGETBV) # old assembler doesn't know the xgetbv instruction
+         endif()
+      endif()
+   endif(APPLE)
+endmacro()
+
+macro(vc_check_fpmath)
+   # if compiling for 32 bit x86 we need to use the -mfpmath=sse since the x87 is broken by design
+   include (CheckCXXSourceRuns)
+   check_cxx_source_runs("int main() { return sizeof(void*) != 8; }" Vc_VOID_PTR_IS_64BIT)
+   if(NOT Vc_VOID_PTR_IS_64BIT)
+      exec_program(${CMAKE_C_COMPILER} ARGS -dumpmachine OUTPUT_VARIABLE _gcc_machine)
+      if(_gcc_machine MATCHES "[x34567]86")
+         vc_add_compiler_flag(Vc_DEFINITIONS "-mfpmath=sse")
+      endif(_gcc_machine MATCHES "[x34567]86")
+   endif()
+endmacro()
+
+macro(vc_set_preferred_compiler_flags)
+   vc_determine_compiler()
+
+   set(_add_warning_flags false)
+   set(_add_buildtype_flags false)
+   foreach(_arg ${ARGN})
+      if(_arg STREQUAL "WARNING_FLAGS")
+         set(_add_warning_flags true)
+      elseif(_arg STREQUAL "BUILDTYPE_FLAGS")
+         set(_add_buildtype_flags true)
+      endif()
+   endforeach()
+
+   set(Vc_SSE_INTRINSICS_BROKEN false)
+   set(Vc_AVX_INTRINSICS_BROKEN false)
+
+   if(Vc_COMPILER_IS_OPEN64)
+      ##################################################################################################
+      #                                             Open64                                             #
+      ##################################################################################################
+      if(_add_warning_flags)
+         AddCompilerFlag("-W")
+         AddCompilerFlag("-Wall")
+         AddCompilerFlag("-Wimplicit")
+         AddCompilerFlag("-Wswitch")
+         AddCompilerFlag("-Wformat")
+         AddCompilerFlag("-Wchar-subscripts")
+         AddCompilerFlag("-Wparentheses")
+         AddCompilerFlag("-Wmultichar")
+         AddCompilerFlag("-Wtrigraphs")
+         AddCompilerFlag("-Wpointer-arith")
+         AddCompilerFlag("-Wcast-align")
+         AddCompilerFlag("-Wreturn-type")
+         AddCompilerFlag("-Wno-unused-function")
+         AddCompilerFlag("-ansi")
+         AddCompilerFlag("-pedantic")
+         AddCompilerFlag("-Wno-long-long")
+         AddCompilerFlag("-Wshadow")
+         AddCompilerFlag("-Wold-style-cast")
+         AddCompilerFlag("-Wno-variadic-macros")
+      endif()
+      if(_add_buildtype_flags)
+         vc_set_gnu_buildtype_flags()
+      endif()
+
+      vc_check_assembler()
+   elseif(Vc_COMPILER_IS_GCC)
+      ##################################################################################################
+      #                                              GCC                                               #
+      ##################################################################################################
+      if(_add_warning_flags)
+         set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wswitch -Wformat -Wchar-subscripts -Wparentheses -Wmultichar -Wtrigraphs -Wpointer-arith -Wcast-align -Wreturn-type -Wno-unused-function -ansi -pedantic -Wno-long-long -Wshadow")
+         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wswitch -Wformat -Wchar-subscripts -Wparentheses -Wmultichar -Wtrigraphs -Wpointer-arith -Wcast-align -Wreturn-type -Wno-unused-function -ansi -pedantic -Wno-long-long -Wshadow")
+         AddCompilerFlag("-Wimplicit")
+         AddCompilerFlag("-Wold-style-cast")
+         AddCompilerFlag("-Wno-variadic-macros")
+         if(Vc_GCC_VERSION VERSION_GREATER "4.5.2" AND Vc_GCC_VERSION VERSION_LESS "4.6.4")
+            # GCC gives bogus "array subscript is above array bounds" warnings in math.cpp
+            AddCompilerFlag("-Wno-array-bounds")
+         endif()
+      endif()
+      vc_add_compiler_flag(Vc_DEFINITIONS "-Wabi")
+      vc_add_compiler_flag(Vc_DEFINITIONS "-fabi-version=0") # ABI version 4 is required to make __m128 and __m256 appear as different types. 0 should give us the latest version.
+
+      if(_add_buildtype_flags)
+         vc_set_gnu_buildtype_flags()
+      endif()
+
+      # GCC 4.5.[01] fail at inlining some functions, creating functions with a single instructions,
+      # thus creating a large overhead.
+      if(Vc_GCC_VERSION VERSION_LESS "4.5.2" AND NOT Vc_GCC_VERSION VERSION_LESS "4.5.0")
+         UserWarning("GCC 4.5.0 and 4.5.1 have problems with inlining correctly. Setting early-inlining-insns=12 as workaround.")
+         AddCompilerFlag("--param early-inlining-insns=12")
+      endif()
+
+      if(Vc_GCC_VERSION VERSION_LESS "4.4.6")
+         UserWarning("Your GCC is older than 4.4.6. This is known to cause problems/bugs. Please update to the latest GCC if you can.")
+         set(Vc_AVX_INTRINSICS_BROKEN true)
+         if(Vc_GCC_VERSION VERSION_LESS "4.3.0")
+            UserWarning("Your GCC is older than 4.3.0. It is unable to handle the full set of SSE2 intrinsics. All SSE code will be disabled. Please update to the latest GCC if you can.")
+            set(Vc_SSE_INTRINSICS_BROKEN true)
+         endif()
+      endif()
+
+      if(Vc_GCC_VERSION VERSION_LESS 4.5.0)
+         UserWarning("GCC 4.4.x shows false positives for -Wparentheses, thus we rather disable the warning.")
+         string(REPLACE " -Wparentheses " " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+         string(REPLACE " -Wparentheses " " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+         set(Vc_DEFINITIONS "${Vc_DEFINITIONS} -Wno-parentheses")
+      elseif(Vc_GCC_VERSION VERSION_EQUAL 4.7.0)
+         UserWarning("GCC 4.7.0 miscompiles at -O3, adding -fno-predictive-commoning to the compiler flags as workaround")
+         set(Vc_DEFINITIONS "${Vc_DEFINITIONS} -fno-predictive-commoning")
+      endif()
+
+      vc_check_fpmath()
+      vc_check_assembler()
+   elseif(Vc_COMPILER_IS_INTEL)
+      ##################################################################################################
+      #                                          Intel Compiler                                        #
+      ##################################################################################################
+
+      if(_add_buildtype_flags)
+         set(CMAKE_CXX_FLAGS_RELEASE        "${CMAKE_CXX_FLAGS_RELEASE} -O3")
+         set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DNDEBUG -O3")
+         set(CMAKE_C_FLAGS_RELEASE          "${CMAKE_C_FLAGS_RELEASE} -O3")
+         set(CMAKE_C_FLAGS_RELWITHDEBINFO   "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DNDEBUG -O3")
+
+         set(ALIAS_FLAGS "-no-ansi-alias")
+         if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+            # default ICC to -no-ansi-alias because otherwise tests/utils_sse fails. So far I suspect a miscompilation...
+            set(ENABLE_STRICT_ALIASING false CACHE BOOL "Enables strict aliasing rules for more aggressive optimizations")
+            if(ENABLE_STRICT_ALIASING)
+               set(ALIAS_FLAGS "-ansi-alias")
+            endif(ENABLE_STRICT_ALIASING)
+         endif()
+         set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   ${ALIAS_FLAGS}")
+         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ALIAS_FLAGS}")
+      endif()
+      vc_add_compiler_flag(Vc_DEFINITIONS "-diag-disable 913")
+   elseif(Vc_COMPILER_IS_MSVC)
+      if(_add_warning_flags)
+         AddCompilerFlag("/wd4800") # Disable warning "forcing value to bool"
+         AddCompilerFlag("/wd4996") # Disable warning about strdup vs. _strdup
+         AddCompilerFlag("/wd4244") # Disable warning "conversion from 'unsigned int' to 'float', possible loss of data"
+         AddCompilerFlag("/wd4146") # Disable warning "unary minus operator applied to unsigned type, result still unsigned"
+         AddCompilerFlag("/wd4227") # Disable warning "anachronism used : qualifiers on reference are ignored" (this is about 'restrict' usage on references, stupid MSVC)
+         AddCompilerFlag("/wd4722") # Disable warning "destructor never returns, potential memory leak" (warns about ~_UnitTest_Global_Object which we don't care about)
+         AddCompilerFlag("/wd4748") # Disable warning "/GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function" (I don't get it)
+         add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+      endif()
+
+      # MSVC does not support inline assembly on 64 bit! :(
+      # searching the help for xgetbv doesn't turn up anything. So just fall back to not supporting AVX on Windows :(
+      # TODO: apparently MSVC 2010 SP1 added _xgetbv
+      set(Vc_DEFINITIONS "${Vc_DEFINITIONS} -DVC_NO_XGETBV")
+
+      # get rid of the min/max macros
+      set(Vc_DEFINITIONS "${Vc_DEFINITIONS} -DNOMINMAX")
+   elseif(Vc_COMPILER_IS_CLANG)
+      # for now I don't know of any arguments I want to pass. -march and stuff is tried by OptimizeForArchitecture...
+
+      # disable these warnings because clang shows them for function overloads that were discarded via SFINAE
+      vc_add_compiler_flag(Vc_DEFINITIONS "-Wno-local-type-template-args")
+      vc_add_compiler_flag(Vc_DEFINITIONS "-Wno-unnamed-type-template-args")
+   endif()
+
+   OptimizeForArchitecture()
+   set(Vc_DEFINITIONS "${Vc_ARCHITECTURE_FLAGS} ${Vc_DEFINITIONS}")
+
+   set(VC_IMPL "auto" CACHE STRING "Force the Vc implementation globally to the selected instruction set. \"auto\" lets Vc use the best available instructions.")
+   if(NOT VC_IMPL STREQUAL "auto")
+      set(Vc_DEFINITIONS "${Vc_DEFINITIONS} -DVC_IMPL=${VC_IMPL}")
+      if(NOT VC_IMPL STREQUAL "Scalar")
+         set(_use_var "USE_${VC_IMPL}")
+         if(VC_IMPL STREQUAL "SSE")
+            set(_use_var "USE_SSE2")
+         endif()
+         if(NOT ${_use_var})
+            message(WARNING "The selected value for VC_IMPL (${VC_IMPL}) will not work because the relevant instructions are not enabled via compiler flags.")
+         endif()
+      endif()
+   endif()
+endmacro()
diff --git a/Vc/include/Vc/IO b/Vc/include/Vc/IO
new file mode 100644 (file)
index 0000000..ec91b6f
--- /dev/null
@@ -0,0 +1,195 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VECIO_H
+#define VECIO_H
+
+#include "vector.h"
+#include "Memory"
+#include <iostream>
+
+#ifdef __GNUC__
+#include <unistd.h>
+#include <ext/stdio_sync_filebuf.h>
+#endif
+
+#include "internal/namespace.h"
+
+namespace
+{
+    namespace AnsiColor
+    {
+        struct Type { const char *data; };
+        static const Type green  = { "\033[1;40;32m" };
+        static const Type yellow = { "\033[1;40;33m" };
+        static const Type blue   = { "\033[1;40;34m" };
+        static const Type normal = { "\033[0m" };
+    } // namespace AnsiColor
+
+#ifdef __GNUC__
+    class hacked_ostream : public std::ostream
+    {
+        public:
+            using std::ostream::_M_streambuf;
+    };
+    static bool mayUseColor(const std::ostream &os)
+        __attribute__((__const__));
+    static bool mayUseColor(const std::ostream &os)
+    {
+        std::basic_streambuf<char> *hack1 = const_cast<std::basic_streambuf<char> *>(os.*(&hacked_ostream::_M_streambuf));
+        __gnu_cxx::stdio_sync_filebuf<char> *hack = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char> *>(hack1);
+        if (!hack) {
+            return false;
+        }
+        FILE *file = hack->file();
+        return 1 == isatty(fileno(file));
+    }
+#else
+    static bool mayUseColor(const std::ostream &) { return false; }
+#endif
+} // anonymous namespace
+
+namespace std
+{
+inline std::ostream &operator<<(std::ostream &out, const AnsiColor::Type &c)
+{
+    if (mayUseColor(out)) {
+        out << c.data;
+    }
+    return out;
+}
+
+template<typename T>
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Vector<T> &v)
+{
+    out << AnsiColor::green << "[";
+    out << v[0];
+    for (int i = 1; i < v.Size; ++i) {
+        out << ", " << v[i];
+    }
+    out << "]" << AnsiColor::normal;
+    return out;
+}
+
+template<>
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Vector<char> &v)
+{
+    out << AnsiColor::green << "[";
+    out << int(v[0]);
+    for (int i = 1; i < v.Size; ++i) {
+        out << ", " << int(v[i]);
+    }
+    out << "]" << AnsiColor::normal;
+    return out;
+}
+template<>
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Vector<unsigned char> &v)
+{
+    out << AnsiColor::green << "[";
+    out << int(v[0]);
+    for (int i = 1; i < v.Size; ++i) {
+        out << ", " << int(v[i]);
+    }
+    out << "]" << AnsiColor::normal;
+    return out;
+}
+
+#ifdef VC_HAVE_FMA
+template<typename T>
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::VectorMultiplication<T> &v)
+{
+    return out << VECTOR_NAMESPACE::Vector<T>(v);
+}
+#endif
+
+#ifdef VC_IMPL_AVX
+template<unsigned int VectorSize, size_t RegisterWidth>
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Mask<VectorSize, RegisterWidth> &m)
+#else
+template<unsigned int VectorSize>
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Mask<VectorSize> &m)
+#endif
+{
+    out << AnsiColor::blue << "m[";
+    for (unsigned int i = 0; i < VectorSize; ++i) {
+        if (i > 0 && (i % 4) == 0) {
+            out << " ";
+        }
+        if ( m[i] ) {
+          out << AnsiColor::yellow << '1';
+        } else {
+          out << AnsiColor::blue << '0';
+        }
+    }
+    out << AnsiColor::blue << "]" << AnsiColor::normal;
+    return out;
+}
+#if VC_IMPL_SSE
+inline std::ostream &operator<<(std::ostream &out, const VECTOR_NAMESPACE::Float8Mask &m)
+{
+    out << AnsiColor::blue << "m[";
+    for (unsigned int i = 0; i < 8; ++i) {
+        if (i > 0 && (i % 4) == 0) {
+            out << " ";
+        }
+        if ( m[i] ) {
+          out << AnsiColor::yellow << '1';
+        } else {
+          out << AnsiColor::blue << '0';
+        }
+    }
+    out << AnsiColor::blue << "]" << AnsiColor::normal;
+    return out;
+}
+#endif
+
+template<typename V, typename Parent, typename RM>
+inline std::ostream &operator<<(std::ostream &out, const Vc::MemoryBase<V, Parent, 1, RM> &m )
+{
+    out << AnsiColor::blue << "{" << AnsiColor::normal;
+    for (unsigned int i = 0; i < m.vectorsCount(); ++i) {
+        out << V(m.vector(i));
+    }
+    out << AnsiColor::blue << "}" << AnsiColor::normal;
+    return out;
+}
+
+template<typename V, typename Parent, typename RM>
+inline std::ostream &operator<<(std::ostream &out, const Vc::MemoryBase<V, Parent, 2, RM> &m )
+{
+    out << AnsiColor::blue << "{" << AnsiColor::normal;
+    for (size_t i = 0; i < m.rowsCount(); ++i) {
+        if (i > 0) {
+            out << "\n ";
+        }
+        const size_t vcount = m[i].vectorsCount();
+        for (size_t j = 0; j < vcount; ++j) {
+            out << V(m[i].vector(j));
+        }
+    }
+    out << AnsiColor::blue << "}" << AnsiColor::normal;
+    return out;
+}
+} // namespace std
+
+#undef VECTOR_NAMESPACE
+
+#endif // VECIO_H
+
+// vim: ft=cpp
diff --git a/Vc/include/Vc/Memory b/Vc/include/Vc/Memory
new file mode 100644 (file)
index 0000000..52a83bc
--- /dev/null
@@ -0,0 +1,27 @@
+
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef INCLUDE_VC_MEMORY
+#define INCLUDE_VC_MEMORY
+
+#include "vector.h"
+#include "common/memory.h"
+
+#endif // INCLUDE_VC_MEMORY
diff --git a/Vc/include/Vc/Utils b/Vc/include/Vc/Utils
new file mode 100644 (file)
index 0000000..132109b
--- /dev/null
@@ -0,0 +1,33 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_UTILS
+#define VC_UTILS
+
+#include "global.h"
+
+#if VC_IMPL_Scalar
+# define VECTOR_NAMESPACE Scalar
+#else
+# define VECTOR_NAMESPACE SSE
+#endif
+
+#include "common/deinterleave.h"
+
+#endif // VC_UTILS
diff --git a/Vc/include/Vc/Vc b/Vc/include/Vc/Vc
new file mode 100644 (file)
index 0000000..f23e7f2
--- /dev/null
@@ -0,0 +1,26 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_VC
+#define VC_VC
+#include "vector.h"
+#include "IO"
+#include "Memory"
+#include "Utils"
+#endif // VC_VC
diff --git a/Vc/include/Vc/avx/casts.h b/Vc/include/Vc/avx/casts.h
new file mode 100644 (file)
index 0000000..8db5d6e
--- /dev/null
@@ -0,0 +1,143 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AVX_CASTS_H
+#define AVX_CASTS_H
+
+#include "intrinsics.h"
+#include "types.h"
+
+namespace Vc
+{
+namespace AVX
+{
+    template<typename T> static inline INTRINSIC_L T avx_cast(__m128  v) INTRINSIC_R;
+    template<typename T> static inline INTRINSIC_L T avx_cast(__m128i v) INTRINSIC_R;
+    template<typename T> static inline INTRINSIC_L T avx_cast(__m128d v) INTRINSIC_R;
+    template<typename T> static inline INTRINSIC_L T avx_cast(__m256  v) INTRINSIC_R;
+    template<typename T> static inline INTRINSIC_L T avx_cast(__m256i v) INTRINSIC_R;
+    template<typename T> static inline INTRINSIC_L T avx_cast(__m256d v) INTRINSIC_R;
+
+    // 128 -> 128
+    template<> inline __m128  INTRINSIC avx_cast(__m128  v) { return v; }
+    template<> inline __m128  INTRINSIC avx_cast(__m128i v) { return _mm_castsi128_ps(v); }
+    template<> inline __m128  INTRINSIC avx_cast(__m128d v) { return _mm_castpd_ps(v); }
+    template<> inline __m128i INTRINSIC avx_cast(__m128  v) { return _mm_castps_si128(v); }
+    template<> inline __m128i INTRINSIC avx_cast(__m128i v) { return v; }
+    template<> inline __m128i INTRINSIC avx_cast(__m128d v) { return _mm_castpd_si128(v); }
+    template<> inline __m128d INTRINSIC avx_cast(__m128  v) { return _mm_castps_pd(v); }
+    template<> inline __m128d INTRINSIC avx_cast(__m128i v) { return _mm_castsi128_pd(v); }
+    template<> inline __m128d INTRINSIC avx_cast(__m128d v) { return v; }
+
+    // 128 -> 256
+    template<> inline __m256  INTRINSIC avx_cast(__m128  v) { return _mm256_castps128_ps256(v); }
+    template<> inline __m256  INTRINSIC avx_cast(__m128i v) { return _mm256_castps128_ps256(_mm_castsi128_ps(v)); }
+    template<> inline __m256  INTRINSIC avx_cast(__m128d v) { return _mm256_castps128_ps256(_mm_castpd_ps(v)); }
+    template<> inline __m256i INTRINSIC avx_cast(__m128  v) { return _mm256_castsi128_si256(_mm_castps_si128(v)); }
+    template<> inline __m256i INTRINSIC avx_cast(__m128i v) { return _mm256_castsi128_si256(v); }
+    template<> inline __m256i INTRINSIC avx_cast(__m128d v) { return _mm256_castsi128_si256(_mm_castpd_si128(v)); }
+    template<> inline __m256d INTRINSIC avx_cast(__m128  v) { return _mm256_castpd128_pd256(_mm_castps_pd(v)); }
+    template<> inline __m256d INTRINSIC avx_cast(__m128i v) { return _mm256_castpd128_pd256(_mm_castsi128_pd(v)); }
+    template<> inline __m256d INTRINSIC avx_cast(__m128d v) { return _mm256_castpd128_pd256(v); }
+
+    // 256 -> 128
+    template<> inline __m128  INTRINSIC avx_cast(__m256  v) { return _mm256_castps256_ps128(v); }
+    template<> inline __m128  INTRINSIC avx_cast(__m256i v) { return _mm256_castps256_ps128(_mm256_castsi256_ps(v)); }
+    template<> inline __m128  INTRINSIC avx_cast(__m256d v) { return _mm256_castps256_ps128(_mm256_castpd_ps(v)); }
+    template<> inline __m128i INTRINSIC avx_cast(__m256  v) { return _mm256_castsi256_si128(_mm256_castps_si256(v)); }
+    template<> inline __m128i INTRINSIC avx_cast(__m256i v) { return _mm256_castsi256_si128(v); }
+    template<> inline __m128i INTRINSIC avx_cast(__m256d v) { return _mm256_castsi256_si128(_mm256_castpd_si256(v)); }
+    template<> inline __m128d INTRINSIC avx_cast(__m256  v) { return _mm256_castpd256_pd128(_mm256_castps_pd(v)); }
+    template<> inline __m128d INTRINSIC avx_cast(__m256i v) { return _mm256_castpd256_pd128(_mm256_castsi256_pd(v)); }
+    template<> inline __m128d INTRINSIC avx_cast(__m256d v) { return _mm256_castpd256_pd128(v); }
+
+    // 256 -> 256
+    template<> inline __m256  INTRINSIC avx_cast(__m256  v) { return v; }
+    template<> inline __m256  INTRINSIC avx_cast(__m256i v) { return _mm256_castsi256_ps(v); }
+    template<> inline __m256  INTRINSIC avx_cast(__m256d v) { return _mm256_castpd_ps(v); }
+    template<> inline __m256i INTRINSIC avx_cast(__m256  v) { return _mm256_castps_si256(v); }
+    template<> inline __m256i INTRINSIC avx_cast(__m256i v) { return v; }
+    template<> inline __m256i INTRINSIC avx_cast(__m256d v) { return _mm256_castpd_si256(v); }
+    template<> inline __m256d INTRINSIC avx_cast(__m256  v) { return _mm256_castps_pd(v); }
+    template<> inline __m256d INTRINSIC avx_cast(__m256i v) { return _mm256_castsi256_pd(v); }
+    template<> inline __m256d INTRINSIC avx_cast(__m256d v) { return v; }
+
+    // simplify splitting 256-bit registers in 128-bit registers
+    inline __m128  INTRINSIC lo128(__m256  v) { return avx_cast<__m128>(v); }
+    inline __m128d INTRINSIC lo128(__m256d v) { return avx_cast<__m128d>(v); }
+    inline __m128i INTRINSIC lo128(__m256i v) { return avx_cast<__m128i>(v); }
+    inline __m128  INTRINSIC hi128(__m256  v) { return _mm256_extractf128_ps(v, 1); }
+    inline __m128d INTRINSIC hi128(__m256d v) { return _mm256_extractf128_pd(v, 1); }
+    inline __m128i INTRINSIC hi128(__m256i v) { return _mm256_extractf128_si256(v, 1); }
+
+    // simplify combining 128-bit registers in 256-bit registers
+    inline __m256  INTRINSIC concat(__m128  a, __m128  b) { return _mm256_insertf128_ps   (avx_cast<__m256 >(a), b, 1); }
+    inline __m256d INTRINSIC concat(__m128d a, __m128d b) { return _mm256_insertf128_pd   (avx_cast<__m256d>(a), b, 1); }
+    inline __m256i INTRINSIC concat(__m128i a, __m128i b) { return _mm256_insertf128_si256(avx_cast<__m256i>(a), b, 1); }
+
+    template<typename From, typename To> struct StaticCastHelper {};
+    template<> struct StaticCastHelper<float         , int           > { static _M256I  cast(const _M256   v) { return _mm256_cvttps_epi32(v); } };
+    template<> struct StaticCastHelper<double        , int           > { static _M256I  cast(const _M256D  v) { return avx_cast<_M256I>(_mm256_cvttpd_epi32(v)); } };
+    template<> struct StaticCastHelper<int           , int           > { static _M256I  cast(const _M256I  v) { return v; } };
+    template<> struct StaticCastHelper<unsigned int  , int           > { static _M256I  cast(const _M256I  v) { return v; } };
+    template<> struct StaticCastHelper<short         , int           > { static _M256I  cast(const __m128i v) { return concat(_mm_srai_epi32(_mm_unpacklo_epi16(v, v), 16), _mm_srai_epi32(_mm_unpackhi_epi16(v, v), 16)); } };
+    template<> struct StaticCastHelper<float         , unsigned int  > { static _M256I  cast(const _M256   v) {
+        return _mm256_castps_si256(_mm256_blendv_ps(
+                _mm256_castsi256_ps(_mm256_cvttps_epi32(v)),
+                _mm256_castsi256_ps(_mm256_add_epi32(_mm256_cvttps_epi32(_mm256_sub_ps(v, _mm256_set2power31_ps())), _mm256_set2power31_epu32())),
+                _mm256_cmpge_ps(v, _mm256_set2power31_ps())
+                ));
+
+    } };
+    template<> struct StaticCastHelper<double        , unsigned int  > { static _M256I  cast(const _M256D  v) { return avx_cast<_M256I>(_mm256_cvttpd_epi32(v)); } };
+    template<> struct StaticCastHelper<int           , unsigned int  > { static _M256I  cast(const _M256I  v) { return v; } };
+    template<> struct StaticCastHelper<unsigned int  , unsigned int  > { static _M256I  cast(const _M256I  v) { return v; } };
+    template<> struct StaticCastHelper<unsigned short, unsigned int  > { static _M256I  cast(const __m128i v) { return concat(_mm_srli_epi32(_mm_unpacklo_epi16(v, v), 16), _mm_srli_epi32(_mm_unpackhi_epi16(v, v), 16)); } };
+    template<> struct StaticCastHelper<float         , float         > { static _M256   cast(const _M256   v) { return v; } };
+    template<> struct StaticCastHelper<double        , float         > { static _M256   cast(const _M256D  v) { return avx_cast<_M256>(_mm256_cvtpd_ps(v)); } };
+    template<> struct StaticCastHelper<int           , float         > { static _M256   cast(const _M256I  v) { return _mm256_cvtepi32_ps(v); } };
+    template<> struct StaticCastHelper<unsigned int  , float         > { static _M256   cast(const _M256I  v) {
+        return _mm256_blendv_ps(
+                _mm256_cvtepi32_ps(v),
+                _mm256_add_ps(_mm256_cvtepi32_ps(_mm256_sub_epi32(v, _mm256_set2power31_epu32())), _mm256_set2power31_ps()),
+                _mm256_castsi256_ps(_mm256_cmplt_epi32(v, _mm256_setzero_si256()))
+                );
+    } };
+    template<> struct StaticCastHelper<short         , float         > { static _M256   cast(const __m128i v) { return _mm256_cvtepi32_ps(StaticCastHelper<short, int>::cast(v)); } };
+    template<> struct StaticCastHelper<unsigned short, float         > { static _M256   cast(const __m128i v) { return _mm256_cvtepi32_ps(StaticCastHelper<unsigned short, unsigned int>::cast(v)); } };
+    template<> struct StaticCastHelper<float         , double        > { static _M256D  cast(const _M256   v) { return _mm256_cvtps_pd(avx_cast<__m128>(v)); } };
+    template<> struct StaticCastHelper<double        , double        > { static _M256D  cast(const _M256D  v) { return v; } };
+    template<> struct StaticCastHelper<int           , double        > { static _M256D  cast(const _M256I  v) { return _mm256_cvtepi32_pd(avx_cast<__m128i>(v)); } };
+    template<> struct StaticCastHelper<unsigned int  , double        > { static _M256D  cast(const _M256I  v) { return _mm256_cvtepi32_pd(avx_cast<__m128i>(v)); } };
+    template<> struct StaticCastHelper<int           , short         > { static __m128i cast(const _M256I  v) { return _mm_packs_epi32(lo128(v), hi128(v)); } };
+    template<> struct StaticCastHelper<float         , short         > { static __m128i cast(const _M256   v) { return StaticCastHelper<int, short>::cast(StaticCastHelper<float, int>::cast(v)); } };
+    template<> struct StaticCastHelper<short         , short         > { static __m128i cast(const __m128i v) { return v; } };
+    template<> struct StaticCastHelper<unsigned short, short         > { static __m128i cast(const __m128i v) { return v; } };
+    template<> struct StaticCastHelper<unsigned int  , unsigned short> { static __m128i cast(const _M256I  v) { return _mm_packus_epi32(lo128(v), hi128(v)); } };
+    template<> struct StaticCastHelper<float         , unsigned short> { static __m128i cast(const _M256   v) { return StaticCastHelper<unsigned int, unsigned short>::cast(StaticCastHelper<float, unsigned int>::cast(v)); } };
+    template<> struct StaticCastHelper<short         , unsigned short> { static __m128i cast(const __m128i v) { return v; } };
+    template<> struct StaticCastHelper<unsigned short, unsigned short> { static __m128i cast(const __m128i v) { return v; } };
+    template<> struct StaticCastHelper<sfloat        , short         > { static __m128i cast(const _M256   v) { return StaticCastHelper<int, short>::cast(StaticCastHelper<float, int>::cast(v)); } };
+    template<> struct StaticCastHelper<sfloat        , unsigned short> { static __m128i cast(const _M256   v) { return StaticCastHelper<unsigned int, unsigned short>::cast(StaticCastHelper<float, unsigned int>::cast(v)); } };
+    template<> struct StaticCastHelper<short         , sfloat        > { static _M256   cast(const __m128i v) { return _mm256_cvtepi32_ps(StaticCastHelper<short, int>::cast(v)); } };
+    template<> struct StaticCastHelper<unsigned short, sfloat        > { static _M256   cast(const __m128i v) { return _mm256_cvtepi32_ps(StaticCastHelper<unsigned short, unsigned int>::cast(v)); } };
+} // namespace AVX
+} // namespace Vc
+
+#endif // AVX_CASTS_H
diff --git a/Vc/include/Vc/avx/const.h b/Vc/include/Vc/avx/const.h
new file mode 100644 (file)
index 0000000..2850865
--- /dev/null
@@ -0,0 +1,114 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_CONST_H
+#define VC_AVX_CONST_H
+
+#include <cstddef>
+#include "const_data.h"
+#include "macros.h"
+
+namespace Vc
+{
+namespace AVX
+{
+    template<typename T> class Vector;
+
+    template<typename T> struct IndexesFromZeroData;
+    template<> struct IndexesFromZeroData<int> {
+        static const int *address() { return reinterpret_cast<const int *>(&_IndexesFromZero32[0]); }
+    };
+    template<> struct IndexesFromZeroData<unsigned int> {
+        static const unsigned int *address() { return &_IndexesFromZero32[0]; }
+    };
+    template<> struct IndexesFromZeroData<short> {
+        static const short *address() { return reinterpret_cast<const short *>(&_IndexesFromZero16[0]); }
+    };
+    template<> struct IndexesFromZeroData<unsigned short> {
+        static const unsigned short *address() { return &_IndexesFromZero16[0]; }
+    };
+    template<> struct IndexesFromZeroData<signed char> {
+        static const signed char *address() { return reinterpret_cast<const signed char *>(&_IndexesFromZero8[0]); }
+    };
+    template<> struct IndexesFromZeroData<char> {
+        static const char *address() { return reinterpret_cast<const char *>(&_IndexesFromZero8[0]); }
+    };
+    template<> struct IndexesFromZeroData<unsigned char> {
+        static const unsigned char *address() { return &_IndexesFromZero8[0]; }
+    };
+
+    template<typename T> struct Const
+    {
+        typedef Vector<T> V;
+        typedef typename V::Mask M;
+
+        static inline V CONST_L _1_2pi()  CONST_R { return V(c_sin<T>::data[0]); }
+        static inline V CONST_L _2pi()    CONST_R { return V(c_sin<T>::data[1]); }
+        static inline V CONST_L _pi_2()   CONST_R { return V(c_sin<T>::data[2]); }
+        static inline V CONST_L _pi()     CONST_R { return V(c_sin<T>::data[3]); }
+        static inline V CONST_L _1_3fac() CONST_R { return V(c_sin<T>::data[4]); }
+        static inline V CONST_L _1_5fac() CONST_R { return V(c_sin<T>::data[5]); }
+        static inline V CONST_L _1_7fac() CONST_R { return V(c_sin<T>::data[6]); }
+        static inline V CONST_L _1_9fac() CONST_R { return V(c_sin<T>::data[7]); }
+
+        static inline M CONST_L exponentMask() CONST_R { return M(V(c_log<T>::d(1)).data()); }
+        static inline V CONST_L _1_2()         CONST_R { return V(c_log<T>::d(18)); }
+        static inline V CONST_L _1_sqrt2()     CONST_R { return V(c_log<T>::d(15)); }
+        static inline V CONST_L P(int i)       CONST_R { return V(c_log<T>::d(2 + i)); }
+        static inline V CONST_L Q(int i)       CONST_R { return V(c_log<T>::d(8 + i)); }
+        static inline V CONST_L min()          CONST_R { return V(c_log<T>::d(14)); }
+        static inline V CONST_L ln2_small()    CONST_R { return V(c_log<T>::d(17)); }
+        static inline V CONST_L ln2_large()    CONST_R { return V(c_log<T>::d(16)); }
+        static inline V CONST_L neginf()       CONST_R { return V(c_log<T>::d(13)); }
+        static inline V CONST_L log10_e()      CONST_R { return V(c_log<T>::d(19)); }
+        static inline V CONST_L log2_e()       CONST_R { return V(c_log<T>::d(20)); }
+    };
+
+    template<> struct Const<sfloat>
+    {
+        typedef sfloat_v V;
+        typedef V::Mask M;
+
+        static inline V CONST_L _1_2pi()  CONST_R { return V(c_sin<float>::data[0]); }
+        static inline V CONST_L _2pi()    CONST_R { return V(c_sin<float>::data[1]); }
+        static inline V CONST_L _pi_2()   CONST_R { return V(c_sin<float>::data[2]); }
+        static inline V CONST_L _pi()     CONST_R { return V(c_sin<float>::data[3]); }
+        static inline V CONST_L _1_3fac() CONST_R { return V(c_sin<float>::data[4]); }
+        static inline V CONST_L _1_5fac() CONST_R { return V(c_sin<float>::data[5]); }
+        static inline V CONST_L _1_7fac() CONST_R { return V(c_sin<float>::data[6]); }
+        static inline V CONST_L _1_9fac() CONST_R { return V(c_sin<float>::data[7]); }
+
+        static inline M CONST_L exponentMask() CONST_R { return M(V(c_log<float>::d(1)).data()); }
+        static inline V CONST_L _1_2()         CONST_R { return V(c_log<float>::d(18)); }
+        static inline V CONST_L _1_sqrt2()     CONST_R { return V(c_log<float>::d(15)); }
+        static inline V CONST_L P(int i)       CONST_R { return V(c_log<float>::d(2 + i)); }
+        static inline V CONST_L Q(int i)       CONST_R { return V(c_log<float>::d(8 + i)); }
+        static inline V CONST_L min()          CONST_R { return V(c_log<float>::d(14)); }
+        static inline V CONST_L ln2_small()    CONST_R { return V(c_log<float>::d(17)); }
+        static inline V CONST_L ln2_large()    CONST_R { return V(c_log<float>::d(16)); }
+        static inline V CONST_L neginf()       CONST_R { return V(c_log<float>::d(13)); }
+        static inline V CONST_L log10_e()      CONST_R { return V(c_log<float>::d(19)); }
+        static inline V CONST_L log2_e()       CONST_R { return V(c_log<float>::d(20)); }
+    };
+} // namespace AVX
+} // namespace Vc
+
+#include "undomacros.h"
+
+#endif // VC_AVX_CONST_H
diff --git a/Vc/include/Vc/avx/const_data.h b/Vc/include/Vc/avx/const_data.h
new file mode 100644 (file)
index 0000000..dadc89b
--- /dev/null
@@ -0,0 +1,70 @@
+/*  This file is part of the Vc library. {{{
+
+    Copyright (C) 2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+}}}*/
+
+#ifndef VC_AVX_CONST_DATA_H
+#define VC_AVX_CONST_DATA_H
+
+#include "macros.h"
+namespace Vc
+{
+namespace AVX
+{
+
+ALIGN(64) extern const unsigned int   _IndexesFromZero32[8];
+ALIGN(16) extern const unsigned short _IndexesFromZero16[8];
+ALIGN(16) extern const unsigned char  _IndexesFromZero8[16];
+
+struct STRUCT_ALIGN1(64) c_general
+{
+    static const float oneFloat;
+    static const unsigned int absMaskFloat[2];
+    static const unsigned int signMaskFloat[2];
+    static const unsigned short minShort[2];
+    static const unsigned short one16[2];
+    static const float _2power31;
+    static const double oneDouble;
+    static const unsigned long long frexpMask;
+} STRUCT_ALIGN2(64);
+
+template<typename T> struct c_sin
+{
+    ALIGN(64) static const T data[];
+};
+
+template<typename T> struct c_log
+{
+    typedef float floatAlias MAY_ALIAS;
+    static inline float d(int i) { return *reinterpret_cast<const floatAlias *>(&data[i]); }
+    ALIGN(64) static const unsigned int data[];
+};
+
+template<> struct c_log<double>
+{
+    enum VectorSize { Size = 16 / sizeof(double) };
+    typedef double doubleAlias MAY_ALIAS;
+    static inline double d(int i) { return *reinterpret_cast<const doubleAlias *>(&data[i]); }
+    ALIGN(64) static const unsigned long long data[];
+};
+
+} // namespace AVX
+} // namespace Vc
+
+#include "undomacros.h"
+
+#endif // VC_AVX_CONST_DATA_H
diff --git a/Vc/include/Vc/avx/debug.h b/Vc/include/Vc/avx/debug.h
new file mode 100644 (file)
index 0000000..a71c127
--- /dev/null
@@ -0,0 +1,100 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_DEBUG_H
+#define VC_AVX_DEBUG_H
+
+#ifndef NDEBUG
+#include "vectorbase.h"
+#include <iostream>
+#include <iomanip>
+#endif
+
+namespace Vc
+{
+namespace AVX
+{
+
+#ifdef NDEBUG
+class DebugStream
+{
+    public:
+        DebugStream(const char *, const char *, int) {}
+        template<typename T> inline DebugStream &operator<<(const T &) { return *this; }
+};
+#else
+class DebugStream
+{
+    private:
+        template<typename T, typename V> static void printVector(V _x)
+        {
+            enum { Size = sizeof(V) / sizeof(T) };
+            union { V v; T m[Size]; } x = { _x };
+            std::cerr << '[' << std::setprecision(24) << x.m[0];
+            for (int i = 1; i < Size; ++i) {
+                std::cerr << ", " << std::setprecision(24) << x.m[i];
+            }
+            std::cerr << ']';
+        }
+    public:
+        DebugStream(const char *func, const char *file, int line)
+        {
+            std::cerr << "\033[1;40;33mDEBUG: " << file << ':' << line << ' ' << func << ' ';
+        }
+
+        template<typename T> DebugStream &operator<<(const T &x) { std::cerr << x; return *this; }
+
+        DebugStream &operator<<(__m128 x) {
+            printVector<float, __m128>(x);
+            return *this;
+        }
+        DebugStream &operator<<(__m256 x) {
+            printVector<float, __m256>(x);
+            return *this;
+        }
+        DebugStream &operator<<(__m128d x) {
+            printVector<double, __m128d>(x);
+            return *this;
+        }
+        DebugStream &operator<<(__m256d x) {
+            printVector<double, __m256d>(x);
+            return *this;
+        }
+        DebugStream &operator<<(__m128i x) {
+            printVector<unsigned int, __m128i>(x);
+            return *this;
+        }
+        DebugStream &operator<<(__m256i x) {
+            printVector<unsigned int, __m256i>(x);
+            return *this;
+        }
+
+        ~DebugStream()
+        {
+            std::cerr << "\033[0m" << std::endl;
+        }
+};
+#endif
+
+#define VC_DEBUG ::Vc::AVX::DebugStream(__PRETTY_FUNCTION__, __FILE__, __LINE__)
+
+} // namespace AVX
+} // namespace Vc
+
+#endif // VC_AVX_DEBUG_H
diff --git a/Vc/include/Vc/avx/deinterleave.tcc b/Vc/include/Vc/avx/deinterleave.tcc
new file mode 100644 (file)
index 0000000..dd92605
--- /dev/null
@@ -0,0 +1,276 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "macros.h"
+
+namespace Vc
+{
+namespace AVX
+{
+
+inline void deinterleave(double_v &VC_RESTRICT a, double_v &VC_RESTRICT b, double_v &VC_RESTRICT c)
+{   // estimated latency (AVX): 4.5 cycles
+    const __m256d tmp0 = Mem::shuffle128<X0, Y1>(a.data(), b.data());
+    const __m256d tmp1 = Mem::shuffle128<X1, Y0>(a.data(), c.data());
+    const __m256d tmp2 = Mem::shuffle128<X0, Y1>(b.data(), c.data());
+    a.data() = Mem::shuffle<X0, Y1, X2, Y3>(tmp0, tmp1);
+    b.data() = Mem::shuffle<X1, Y0, X3, Y2>(tmp0, tmp2);
+    c.data() = Mem::shuffle<X0, Y1, X2, Y3>(tmp1, tmp2);
+}
+
+inline void deinterleave(float_v &VC_RESTRICT a, float_v &VC_RESTRICT b, float_v &VC_RESTRICT c)
+{
+    //                               abc   abc abc
+    // a = [a0 b0 c0 a1 b1 c1 a2 b2] 332 = 211+121
+    // b = [c2 a3 b3 c3 a4 b4 c4 a5] 323 = 112+211
+    // c = [b5 c5 a6 b6 c6 a7 b7 c7] 233 = 121+112
+    const __m256 ac0 = Mem::shuffle128<X0, Y0>(a.data(), c.data()); // a0 b0 c0 a1 b5 c5 a6 b6
+    const __m256 ac1 = Mem::shuffle128<X1, Y1>(a.data(), c.data()); // b1 c1 a2 b2 c6 a7 b7 c7
+
+    __m256 tmp0 = Mem::blend<X0, Y1, X2, X3, Y4, X5, X6, Y7>( ac0, b.data());
+           tmp0 = Mem::blend<X0, X1, Y2, X3, X4, Y5, X6, X7>(tmp0,      ac1); // a0 a3 a2 a1 a4 a7 a6 a5
+    __m256 tmp1 = Mem::blend<X0, X1, Y2, X3, X4, Y5, X6, X7>( ac0, b.data());
+           tmp1 = Mem::blend<Y0, X1, X2, Y3, X4, X5, Y6, X7>(tmp1,      ac1); // b1 b0 b3 b2 b5 b4 b7 b6
+    __m256 tmp2 = Mem::blend<Y0, X1, X2, Y3, X4, X5, Y6, X7>( ac0, b.data());
+           tmp2 = Mem::blend<X0, Y1, X2, X3, Y4, X5, X6, Y7>(tmp2,      ac1); // c2 c1 c0 c3 c6 c5 c4 c7
+
+    a.data() = Mem::permute<X0, X3, X2, X1>(tmp0);
+    b.data() = Mem::permute<X1, X0, X3, X2>(tmp1);
+    c.data() = Mem::permute<X2, X1, X0, X3>(tmp2);
+}
+
+inline void deinterleave(int_v &VC_RESTRICT a, int_v &VC_RESTRICT b, int_v &VC_RESTRICT c)
+{
+    deinterleave(reinterpret_cast<float_v &>(a), reinterpret_cast<float_v &>(b),
+            reinterpret_cast<float_v &>(c));
+}
+
+inline void deinterleave(uint_v &VC_RESTRICT a, uint_v &VC_RESTRICT b, uint_v &VC_RESTRICT c)
+{
+    deinterleave(reinterpret_cast<float_v &>(a), reinterpret_cast<float_v &>(b),
+            reinterpret_cast<float_v &>(c));
+}
+
+inline void deinterleave(Vector<short> &VC_RESTRICT a, Vector<short> &VC_RESTRICT b,
+        Vector<short> &VC_RESTRICT c)
+{
+    //                               abc   abc abc
+    // a = [a0 b0 c0 a1 b1 c1 a2 b2] 332 = 211+121
+    // b = [c2 a3 b3 c3 a4 b4 c4 a5] 323 = 112+211
+    // c = [b5 c5 a6 b6 c6 a7 b7 c7] 233 = 121+112
+    __m128i ac0 = _mm_unpacklo_epi64(a.data(), c.data()); // a0 b0 c0 a1 b5 c5 a6 b6
+    __m128i ac1 = _mm_unpackhi_epi64(a.data(), c.data()); // b1 c1 a2 b2 c6 a7 b7 c7
+
+    __m128i tmp0 = Mem::blend<X0, Y1, X2, X3, Y4, X5, X6, Y7>( ac0, b.data());
+            tmp0 = Mem::blend<X0, X1, Y2, X3, X4, Y5, X6, X7>(tmp0,      ac1); // a0 a3 a2 a1 a4 a7 a6 a5
+    __m128i tmp1 = Mem::blend<X0, X1, Y2, X3, X4, Y5, X6, X7>( ac0, b.data());
+            tmp1 = Mem::blend<Y0, X1, X2, Y3, X4, X5, Y6, X7>(tmp1,      ac1); // b1 b0 b3 b2 b5 b4 b7 b6
+    __m128i tmp2 = Mem::blend<Y0, X1, X2, Y3, X4, X5, Y6, X7>( ac0, b.data());
+            tmp2 = Mem::blend<X0, Y1, X2, X3, Y4, X5, X6, Y7>(tmp2,      ac1); // c2 c1 c0 c3 c6 c5 c4 c7
+
+    a.data() = Mem::permuteHi<X4, X7, X6, X5>(Mem::permuteLo<X0, X3, X2, X1>(tmp0));
+    b.data() = Mem::permuteHi<X5, X4, X7, X6>(Mem::permuteLo<X1, X0, X3, X2>(tmp1));
+    c.data() = Mem::permuteHi<X6, X5, X4, X7>(Mem::permuteLo<X2, X1, X0, X3>(tmp2));
+}
+
+inline void deinterleave(Vector<unsigned short> &VC_RESTRICT a, Vector<unsigned short> &VC_RESTRICT b,
+        Vector<unsigned short> &VC_RESTRICT c)
+{
+    deinterleave(reinterpret_cast<Vector<short> &>(a), reinterpret_cast<Vector<short> &>(b),
+            reinterpret_cast<Vector<short> &>(c));
+}
+
+inline void deinterleave(Vector<float> &a, Vector<float> &b)
+{
+    // a7 a6 a5 a4 a3 a2 a1 a0
+    // b7 b6 b5 b4 b3 b2 b1 b0
+    const _M256 tmp0 = Reg::permute128<Y0, X0>(a.data(), b.data()); // b3 b2 b1 b0 a3 a2 a1 a0
+    const _M256 tmp1 = Reg::permute128<Y1, X1>(a.data(), b.data()); // b7 b6 b5 b4 a7 a6 a5 a4
+
+    const _M256 tmp2 = _mm256_unpacklo_ps(tmp0, tmp1); // b5 b1 b4 b0 a5 a1 a4 a0
+    const _M256 tmp3 = _mm256_unpackhi_ps(tmp0, tmp1); // b7 b3 b6 b2 a7 a3 a6 a2
+
+    a.data() = _mm256_unpacklo_ps(tmp2, tmp3); // b6 b4 b2 b0 a6 a4 a2 a0
+    b.data() = _mm256_unpackhi_ps(tmp2, tmp3); // b7 b5 b3 b1 a7 a5 a3 a1
+}
+
+inline void deinterleave(Vector<short> &a, Vector<short> &b)
+{
+    __m128i tmp0 = _mm_unpacklo_epi16(a.data(), b.data()); // a0 a4 b0 b4 a1 a5 b1 b5
+    __m128i tmp1 = _mm_unpackhi_epi16(a.data(), b.data()); // a2 a6 b2 b6 a3 a7 b3 b7
+    __m128i tmp2 = _mm_unpacklo_epi16(tmp0, tmp1); // a0 a2 a4 a6 b0 b2 b4 b6
+    __m128i tmp3 = _mm_unpackhi_epi16(tmp0, tmp1); // a1 a3 a5 a7 b1 b3 b5 b7
+    a.data() = _mm_unpacklo_epi16(tmp2, tmp3);
+    b.data() = _mm_unpackhi_epi16(tmp2, tmp3);
+}
+
+inline void deinterleave(Vector<unsigned short> &a, Vector<unsigned short> &b)
+{
+    __m128i tmp0 = _mm_unpacklo_epi16(a.data(), b.data()); // a0 a4 b0 b4 a1 a5 b1 b5
+    __m128i tmp1 = _mm_unpackhi_epi16(a.data(), b.data()); // a2 a6 b2 b6 a3 a7 b3 b7
+    __m128i tmp2 = _mm_unpacklo_epi16(tmp0, tmp1); // a0 a2 a4 a6 b0 b2 b4 b6
+    __m128i tmp3 = _mm_unpackhi_epi16(tmp0, tmp1); // a1 a3 a5 a7 b1 b3 b5 b7
+    a.data() = _mm_unpacklo_epi16(tmp2, tmp3);
+    b.data() = _mm_unpackhi_epi16(tmp2, tmp3);
+}
+
+} // namespace AVX
+
+
+namespace Internal
+{
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        float_v &a, float_v &b, const float *m, A align)
+{
+    a.load(m, align);
+    b.load(m + float_v::Size, align);
+    Vc::AVX::deinterleave(a, b);
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        float_v &a, float_v &b, const short *m, A align)
+{
+    const __m256i tmp = Vc::AVX::VectorHelper<__m256i>::load(m, align);
+    a.data() = _mm256_cvtepi32_ps(Vc::AVX::concat(
+                _mm_srai_epi32(_mm_slli_epi32(AVX::lo128(tmp), 16), 16),
+                _mm_srai_epi32(_mm_slli_epi32(AVX::hi128(tmp), 16), 16)));
+    b.data() = _mm256_cvtepi32_ps(Vc::AVX::concat(
+                _mm_srai_epi32(AVX::lo128(tmp), 16),
+                _mm_srai_epi32(AVX::hi128(tmp), 16)));
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        float_v &a, float_v &b, const unsigned short *m, A align)
+{
+    const __m256i tmp = Vc::AVX::VectorHelper<__m256i>::load(m, align);
+    a.data() = _mm256_cvtepi32_ps(Vc::AVX::concat(
+                _mm_blend_epi16(AVX::lo128(tmp), _mm_setzero_si128(), 0xaa),
+                _mm_blend_epi16(AVX::hi128(tmp), _mm_setzero_si128(), 0xaa)));
+    b.data() = _mm256_cvtepi32_ps(Vc::AVX::concat(
+                _mm_srli_epi32(AVX::lo128(tmp), 16),
+                _mm_srli_epi32(AVX::hi128(tmp), 16)));
+}
+
+template<typename A, typename MemT> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        sfloat_v &_a, sfloat_v &_b, const MemT *m, A align)
+{
+    float_v &a = reinterpret_cast<float_v &>(_a);
+    float_v &b = reinterpret_cast<float_v &>(_b);
+    HelperImpl<Vc::AVXImpl>::deinterleave(a, b, m, align);
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        double_v &a, double_v &b, const double *m, A align)
+{
+    a.load(m, align);
+    b.load(m + double_v::Size, align);
+
+    __m256d tmp0 = Mem::shuffle128<Vc::X0, Vc::Y0>(a.data(), b.data()); // b1 b0 a1 a0
+    __m256d tmp1 = Mem::shuffle128<Vc::X1, Vc::Y1>(a.data(), b.data()); // b3 b2 a3 a2
+
+    a.data() = _mm256_unpacklo_pd(tmp0, tmp1); // b2 b0 a2 a0
+    b.data() = _mm256_unpackhi_pd(tmp0, tmp1); // b3 b1 a3 a1
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        int_v &a, int_v &b, const int *m, A align)
+{
+    a.load(m, align);
+    b.load(m + int_v::Size, align);
+
+    const __m256 tmp0 = AVX::avx_cast<__m256>(Mem::shuffle128<Vc::X0, Vc::Y0>(a.data(), b.data()));
+    const __m256 tmp1 = AVX::avx_cast<__m256>(Mem::shuffle128<Vc::X1, Vc::Y1>(a.data(), b.data()));
+
+    const __m256 tmp2 = _mm256_unpacklo_ps(tmp0, tmp1); // b5 b1 b4 b0 a5 a1 a4 a0
+    const __m256 tmp3 = _mm256_unpackhi_ps(tmp0, tmp1); // b7 b3 b6 b2 a7 a3 a6 a2
+
+    a.data() = AVX::avx_cast<__m256i>(_mm256_unpacklo_ps(tmp2, tmp3)); // b6 b4 b2 b0 a6 a4 a2 a0
+    b.data() = AVX::avx_cast<__m256i>(_mm256_unpackhi_ps(tmp2, tmp3)); // b7 b5 b3 b1 a7 a5 a3 a1
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        int_v &a, int_v &b, const short *m, A align)
+{
+    const __m256i tmp = Vc::AVX::VectorHelper<__m256i>::load(m, align);
+    a.data() = Vc::AVX::concat(
+                _mm_srai_epi32(_mm_slli_epi32(AVX::lo128(tmp), 16), 16),
+                _mm_srai_epi32(_mm_slli_epi32(AVX::hi128(tmp), 16), 16));
+    b.data() = Vc::AVX::concat(
+                _mm_srai_epi32(AVX::lo128(tmp), 16),
+                _mm_srai_epi32(AVX::hi128(tmp), 16));
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        uint_v &a, uint_v &b, const unsigned int *m, A align)
+{
+    a.load(m, align);
+    b.load(m + uint_v::Size, align);
+
+    const __m256 tmp0 = AVX::avx_cast<__m256>(Mem::shuffle128<Vc::X0, Vc::Y0>(a.data(), b.data()));
+    const __m256 tmp1 = AVX::avx_cast<__m256>(Mem::shuffle128<Vc::X1, Vc::Y1>(a.data(), b.data()));
+
+    const __m256 tmp2 = _mm256_unpacklo_ps(tmp0, tmp1); // b5 b1 b4 b0 a5 a1 a4 a0
+    const __m256 tmp3 = _mm256_unpackhi_ps(tmp0, tmp1); // b7 b3 b6 b2 a7 a3 a6 a2
+
+    a.data() = AVX::avx_cast<__m256i>(_mm256_unpacklo_ps(tmp2, tmp3)); // b6 b4 b2 b0 a6 a4 a2 a0
+    b.data() = AVX::avx_cast<__m256i>(_mm256_unpackhi_ps(tmp2, tmp3)); // b7 b5 b3 b1 a7 a5 a3 a1
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        uint_v &a, uint_v &b, const unsigned short *m, A align)
+{
+    const __m256i tmp = Vc::AVX::VectorHelper<__m256i>::load(m, align);
+    a.data() = Vc::AVX::concat(
+                _mm_srli_epi32(_mm_slli_epi32(AVX::lo128(tmp), 16), 16),
+                _mm_srli_epi32(_mm_slli_epi32(AVX::hi128(tmp), 16), 16));
+    b.data() = Vc::AVX::concat(
+                _mm_srli_epi32(AVX::lo128(tmp), 16),
+                _mm_srli_epi32(AVX::hi128(tmp), 16));
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        short_v &a, short_v &b, const short *m, A align)
+{
+    a.load(m, align);
+    b.load(m + short_v::Size, align);
+    Vc::AVX::deinterleave(a, b);
+}
+
+template<typename A> inline void HelperImpl<Vc::AVXImpl>::deinterleave(
+        ushort_v &a, ushort_v &b, const unsigned short *m, A align)
+{
+    a.load(m, align);
+    b.load(m + ushort_v::Size, align);
+    Vc::AVX::deinterleave(a, b);
+}
+
+// only support M == V::EntryType -> no specialization
+template<typename V, typename M, typename A>
+inline void HelperImpl<Vc::AVXImpl>::deinterleave(V &VC_RESTRICT a, V &VC_RESTRICT b,
+        V &VC_RESTRICT c, const M *VC_RESTRICT memory, A align)
+{
+    a.load(&memory[0 * V::Size], align);
+    b.load(&memory[1 * V::Size], align);
+    c.load(&memory[2 * V::Size], align);
+    Vc::AVX::deinterleave(a, b, c);
+}
+
+} // namespace Internal
+} // namespace Vc
diff --git a/Vc/include/Vc/avx/forceToRegisters.tcc b/Vc/include/Vc/avx/forceToRegisters.tcc
new file mode 100644 (file)
index 0000000..583209c
--- /dev/null
@@ -0,0 +1,141 @@
+#ifdef __GNUC__
+template<typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x1.data()));
+}
+template<typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x1.data()));
+}
+template<typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x2.data()), "x"(x1.data()));
+}
+template<typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x2.data()), "+x"(x1.data()));
+}
+template<typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T3> &x3, const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x3.data()), "x"(x2.data()), "x"(x1.data()));
+}
+template<typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T3> &x3, Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x3.data()), "+x"(x2.data()), "+x"(x1.data()));
+}
+template<typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T4> &x4, const Vector<T3> &x3, const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x4.data()), "x"(x3.data()), "x"(x2.data()), "x"(x1.data()));
+}
+template<typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T4> &x4, Vector<T3> &x3, Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x4.data()), "+x"(x3.data()), "+x"(x2.data()), "+x"(x1.data()));
+}
+template<typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T5> &x5, const Vector<T4> &x4, const Vector<T3> &x3, const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x5.data()), "x"(x4.data()), "x"(x3.data()), "x"(x2.data()), "x"(x1.data()));
+}
+template<typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T5> &x5, Vector<T4> &x4, Vector<T3> &x3, Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x5.data()), "+x"(x4.data()), "+x"(x3.data()), "+x"(x2.data()), "+x"(x1.data()));
+}
+template<typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T6> &x6, const Vector<T5> &x5, const Vector<T4> &x4, const Vector<T3> &x3, const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x6.data()), "x"(x5.data()), "x"(x4.data()), "x"(x3.data()), "x"(x2.data()), "x"(x1.data()));
+}
+template<typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T6> &x6, Vector<T5> &x5, Vector<T4> &x4, Vector<T3> &x3, Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x6.data()), "+x"(x5.data()), "+x"(x4.data()), "+x"(x3.data()), "+x"(x2.data()), "+x"(x1.data()));
+}
+template<typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T7> &x7, const Vector<T6> &x6, const Vector<T5> &x5, const Vector<T4> &x4, const Vector<T3> &x3, const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x7.data()), "x"(x6.data()), "x"(x5.data()), "x"(x4.data()), "x"(x3.data()), "x"(x2.data()), "x"(x1.data()));
+}
+template<typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T7> &x7, Vector<T6> &x6, Vector<T5> &x5, Vector<T4> &x4, Vector<T3> &x3, Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x7.data()), "+x"(x6.data()), "+x"(x5.data()), "+x"(x4.data()), "+x"(x3.data()), "+x"(x2.data()), "+x"(x1.data()));
+}
+template<typename T8, typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T8> &x8, const Vector<T7> &x7, const Vector<T6> &x6, const Vector<T5> &x5, const Vector<T4> &x4, const Vector<T3> &x3, const Vector<T2> &x2, const Vector<T1> &x1) {
+  __asm__ __volatile__(""::"x"(x8.data()), "x"(x7.data()), "x"(x6.data()), "x"(x5.data()), "x"(x4.data()), "x"(x3.data()), "x"(x2.data()), "x"(x1.data()));
+}
+template<typename T8, typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T8> &x8, Vector<T7> &x7, Vector<T6> &x6, Vector<T5> &x5, Vector<T4> &x4, Vector<T3> &x3, Vector<T2> &x2, Vector<T1> &x1) {
+  __asm__ __volatile__("":"+x"(x8.data()), "+x"(x7.data()), "+x"(x6.data()), "+x"(x5.data()), "+x"(x4.data()), "+x"(x3.data()), "+x"(x2.data()), "+x"(x1.data()));
+}
+#elif defined(VC_MSVC)
+#pragma optimize("g", off)
+template<typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T3> &/*x3*/, const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T3> &/*x3*/, Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T4> &/*x4*/, const Vector<T3> &/*x3*/, const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T4> &/*x4*/, Vector<T3> &/*x3*/, Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T5> &/*x5*/, const Vector<T4> &/*x4*/, const Vector<T3> &/*x3*/, const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T5> &/*x5*/, Vector<T4> &/*x4*/, Vector<T3> &/*x3*/, Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T6> &/*x6*/, const Vector<T5> &/*x5*/, const Vector<T4> &/*x4*/, const Vector<T3> &/*x3*/, const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T6> &/*x6*/, Vector<T5> &/*x5*/, Vector<T4> &/*x4*/, Vector<T3> &/*x3*/, Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T7> &/*x7*/, const Vector<T6> &/*x6*/, const Vector<T5> &/*x5*/, const Vector<T4> &/*x4*/, const Vector<T3> &/*x3*/, const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T7> &/*x7*/, Vector<T6> &/*x6*/, Vector<T5> &/*x5*/, Vector<T4> &/*x4*/, Vector<T3> &/*x3*/, Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#pragma optimize("g", off)
+template<typename T8, typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegisters(const Vector<T8> &/*x8*/, const Vector<T7> &/*x7*/, const Vector<T6> &/*x6*/, const Vector<T5> &/*x5*/, const Vector<T4> &/*x4*/, const Vector<T3> &/*x3*/, const Vector<T2> &/*x2*/, const Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", off)
+template<typename T8, typename T7, typename T6, typename T5, typename T4, typename T3, typename T2, typename T1>
+static inline void ALWAYS_INLINE forceToRegistersDirty(Vector<T8> &/*x8*/, Vector<T7> &/*x7*/, Vector<T6> &/*x6*/, Vector<T5> &/*x5*/, Vector<T4> &/*x4*/, Vector<T3> &/*x3*/, Vector<T2> &/*x2*/, Vector<T1> &/*x1*/) {
+}
+#pragma optimize("g", on)
+#else
+#error "forceToRegisters unsupported on this compiler"
+#endif
diff --git a/Vc/include/Vc/avx/helperimpl.h b/Vc/include/Vc/avx/helperimpl.h
new file mode 100644 (file)
index 0000000..d665cb5
--- /dev/null
@@ -0,0 +1,102 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_HELPERIMPL_H
+#define VC_AVX_HELPERIMPL_H
+
+#include "macros.h"
+
+namespace Vc
+{
+namespace Internal
+{
+
+template<> struct HelperImpl<Vc::AVXImpl>
+{
+    typedef AVX::Vector<float> float_v;
+    typedef AVX::Vector<sfloat> sfloat_v;
+    typedef AVX::Vector<double> double_v;
+    typedef AVX::Vector<int> int_v;
+    typedef AVX::Vector<unsigned int> uint_v;
+    typedef AVX::Vector<short> short_v;
+    typedef AVX::Vector<unsigned short> ushort_v;
+
+    template<typename A> static void deinterleave(float_v &, float_v &, const float *, A);
+    template<typename A> static void deinterleave(float_v &, float_v &, const short *, A);
+    template<typename A> static void deinterleave(float_v &, float_v &, const unsigned short *, A);
+
+    template<typename A, typename MemT> static void deinterleave(sfloat_v &, sfloat_v &, const MemT *, A);
+
+    template<typename A> static void deinterleave(double_v &, double_v &, const double *, A);
+
+    template<typename A> static void deinterleave(int_v &, int_v &, const int *, A);
+    template<typename A> static void deinterleave(int_v &, int_v &, const short *, A);
+
+    template<typename A> static void deinterleave(uint_v &, uint_v &, const unsigned int *, A);
+    template<typename A> static void deinterleave(uint_v &, uint_v &, const unsigned short *, A);
+
+    template<typename A> static void deinterleave(short_v &, short_v &, const short *, A);
+
+    template<typename A> static void deinterleave(ushort_v &, ushort_v &, const unsigned short *, A);
+
+    template<typename V, typename M, typename A>
+        static inline void deinterleave(V &VC_RESTRICT a, V &VC_RESTRICT b,
+                V &VC_RESTRICT c, const M *VC_RESTRICT memory, A align);
+
+    template<typename V, typename M, typename A>
+        static inline void deinterleave(V &VC_RESTRICT a, V &VC_RESTRICT b,
+                V &VC_RESTRICT c, V &VC_RESTRICT d,
+                const M *VC_RESTRICT memory, A align);
+
+    template<typename V, typename M, typename A>
+        static inline void deinterleave(V &VC_RESTRICT a, V &VC_RESTRICT b,
+                V &VC_RESTRICT c, V &VC_RESTRICT d, V &VC_RESTRICT e,
+                const M *VC_RESTRICT memory, A align);
+
+    template<typename V, typename M, typename A>
+        static inline void deinterleave(V &VC_RESTRICT a, V &VC_RESTRICT b,
+                V &VC_RESTRICT c, V &VC_RESTRICT d, V &VC_RESTRICT e,
+                V &VC_RESTRICT f, const M *VC_RESTRICT memory, A align);
+
+    template<typename V, typename M, typename A>
+        static inline void deinterleave(V &VC_RESTRICT a, V &VC_RESTRICT b,
+                V &VC_RESTRICT c, V &VC_RESTRICT d, V &VC_RESTRICT e,
+                V &VC_RESTRICT f, V &VC_RESTRICT g, V &VC_RESTRICT h,
+                const M *VC_RESTRICT memory, A align);
+
+    static inline void ALWAYS_INLINE_L prefetchForOneRead(const void *addr) ALWAYS_INLINE_R;
+    static inline void ALWAYS_INLINE_L prefetchForModify(const void *addr) ALWAYS_INLINE_R;
+    static inline void ALWAYS_INLINE_L prefetchClose(const void *addr) ALWAYS_INLINE_R;
+    static inline void ALWAYS_INLINE_L prefetchMid(const void *addr) ALWAYS_INLINE_R;
+    static inline void ALWAYS_INLINE_L prefetchFar(const void *addr) ALWAYS_INLINE_R;
+
+    template<Vc::MallocAlignment A>
+    static inline ALWAYS_INLINE_L void *malloc(size_t n) ALWAYS_INLINE_R;
+    static inline ALWAYS_INLINE_L void free(void *p) ALWAYS_INLINE_R;
+};
+
+} // namespace Internal
+} // namespace Vc
+
+#include "undomacros.h"
+#include "deinterleave.tcc"
+#include "prefetches.tcc"
+#include "helperimpl.tcc"
+
+#endif // VC_AVX_HELPERIMPL_H
diff --git a/Vc/include/Vc/avx/helperimpl.tcc b/Vc/include/Vc/avx/helperimpl.tcc
new file mode 100644 (file)
index 0000000..2ca8eb4
--- /dev/null
@@ -0,0 +1,66 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_HELPERIMPL_TCC
+#define VC_AVX_HELPERIMPL_TCC
+
+namespace Vc
+{
+namespace Internal
+{
+
+template<size_t X>
+static inline size_t nextMultipleOf(size_t value)
+{
+    const size_t offset = value % X;
+    if ( offset > 0 ) {
+        return value + X - offset;
+    }
+    return value;
+}
+
+template<Vc::MallocAlignment A>
+inline ALWAYS_INLINE void *HelperImpl<AVXImpl>::malloc(size_t n)
+{
+    switch (A) {
+        case Vc::AlignOnVector:
+            return _mm_malloc(nextMultipleOf<Vc::AVX::VectorAlignment>(n), Vc::AVX::VectorAlignment);
+        case Vc::AlignOnCacheline:
+            // TODO: hardcoding 64 is not such a great idea
+            return _mm_malloc(nextMultipleOf<64>(n), 64);
+        case Vc::AlignOnPage:
+            // TODO: hardcoding 4096 is not such a great idea
+            return _mm_malloc(nextMultipleOf<4096>(n), 4096);
+        default:
+#ifndef NDEBUG
+            abort();
+#endif
+            return _mm_malloc(n, 8);
+    }
+}
+
+inline ALWAYS_INLINE void HelperImpl<AVXImpl>::free(void *p)
+{
+    _mm_free(p);
+}
+
+} // namespace Internal
+} // namespace Vc
+
+#endif // VC_AVX_HELPERIMPL_TCC
diff --git a/Vc/include/Vc/avx/intrinsics.h b/Vc/include/Vc/avx/intrinsics.h
new file mode 100644 (file)
index 0000000..4bb3661
--- /dev/null
@@ -0,0 +1,414 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_INTRINSICS_H
+#define VC_AVX_INTRINSICS_H
+
+#include "../common/windows_fix_intrin.h"
+
+// AVX
+#include <immintrin.h>
+
+#if defined(VC_CLANG) && VC_CLANG < 0x30100
+// _mm_permute_ps is broken: http://llvm.org/bugs/show_bug.cgi?id=12401
+#undef _mm_permute_ps
+#define _mm_permute_ps(A, C) __extension__ ({ \
+  __m128 __A = (A); \
+  (__m128)__builtin_shufflevector((__v4sf)__A, (__v4sf) _mm_setzero_ps(), \
+                                   (C) & 0x3, ((C) & 0xc) >> 2, \
+                                   ((C) & 0x30) >> 4, ((C) & 0xc0) >> 6); })
+#endif
+
+#include <Vc/global.h>
+#include "const_data.h"
+#include "macros.h"
+#include <cstdlib>
+
+#if defined(VC_CLANG) || defined(VC_MSVC) || (defined(VC_GCC) && !defined(__OPTIMIZE__))
+#define VC_REQUIRES_MACRO_FOR_IMMEDIATE_ARGUMENT
+#endif
+
+#if defined(VC_CLANG) && VC_CLANG <= 0x30000
+// _mm_alignr_epi8 doesn't specify its return type, thus breaking overload resolution
+#undef _mm_alignr_epi8
+#define _mm_alignr_epi8(a, b, n) ((__m128i)__builtin_ia32_palignr128((a), (b), (n)))
+#endif
+
+namespace Vc
+{
+namespace AVX
+{
+#if defined(VC_GNU_ASM) && !defined(NVALGRIND)
+    static inline __m128i CONST _mm_setallone() { __m128i r; __asm__("pcmpeqb %0,%0":"=x"(r)); return r; }
+#else
+    static inline __m128i CONST _mm_setallone() { __m128i r = _mm_setzero_si128(); return _mm_cmpeq_epi8(r, r); }
+#endif
+    static inline __m128i CONST _mm_setallone_si128() { return _mm_setallone(); }
+    static inline __m128d CONST _mm_setallone_pd() { return _mm_castsi128_pd(_mm_setallone()); }
+    static inline __m128  CONST _mm_setallone_ps() { return _mm_castsi128_ps(_mm_setallone()); }
+
+    static inline __m128i CONST _mm_setone_epi8 ()  { return _mm_set1_epi8(1); }
+    static inline __m128i CONST _mm_setone_epu8 ()  { return _mm_setone_epi8(); }
+    static inline __m128i CONST _mm_setone_epi16()  { return _mm_castps_si128(_mm_broadcast_ss(reinterpret_cast<const float *>(c_general::one16))); }
+    static inline __m128i CONST _mm_setone_epu16()  { return _mm_setone_epi16(); }
+    static inline __m128i CONST _mm_setone_epi32()  { return _mm_castps_si128(_mm_broadcast_ss(reinterpret_cast<const float *>(&_IndexesFromZero32[1]))); }
+
+#if defined(VC_GNU_ASM) && !defined(NVALGRIND)
+    static inline __m256 CONST _mm256_setallone() { __m256 r; __asm__("vcmpps $8,%0,%0,%0":"=x"(r)); return r; }
+#else
+    static inline __m256 CONST _mm256_setallone() { __m256 r = _mm256_setzero_ps(); return _mm256_cmp_ps(r, r, _CMP_EQ_UQ); }
+#endif
+    static inline __m256i CONST _mm256_setallone_si256() { return _mm256_castps_si256(_mm256_setallone()); }
+    static inline __m256d CONST _mm256_setallone_pd() { return _mm256_castps_pd(_mm256_setallone()); }
+    static inline __m256  CONST _mm256_setallone_ps() { return _mm256_setallone(); }
+
+    static inline __m256i CONST _mm256_setone_epi8 ()  { return _mm256_set1_epi8(1); }
+    static inline __m256i CONST _mm256_setone_epu8 ()  { return _mm256_setone_epi8(); }
+    static inline __m256i CONST _mm256_setone_epi16()  { return _mm256_castps_si256(_mm256_broadcast_ss(reinterpret_cast<const float *>(c_general::one16))); }
+    static inline __m256i CONST _mm256_setone_epu16()  { return _mm256_setone_epi16(); }
+    static inline __m256i CONST _mm256_setone_epi32()  { return _mm256_castps_si256(_mm256_broadcast_ss(reinterpret_cast<const float *>(&_IndexesFromZero32[1]))); }
+    static inline __m256i CONST _mm256_setone_epu32()  { return _mm256_setone_epi32(); }
+
+    static inline __m256  CONST _mm256_setone_ps()     { return _mm256_broadcast_ss(&c_general::oneFloat); }
+    static inline __m256d CONST _mm256_setone_pd()     { return _mm256_broadcast_sd(&c_general::oneDouble); }
+
+    static inline __m256d CONST _mm256_setabsmask_pd() { return _mm256_broadcast_sd(reinterpret_cast<const double *>(&c_general::absMaskFloat[0])); }
+    static inline __m256  CONST _mm256_setabsmask_ps() { return _mm256_broadcast_ss(reinterpret_cast<const float *>(&c_general::absMaskFloat[1])); }
+    static inline __m256d CONST _mm256_setsignmask_pd(){ return _mm256_broadcast_sd(reinterpret_cast<const double *>(&c_general::signMaskFloat[0])); }
+    static inline __m256  CONST _mm256_setsignmask_ps(){ return _mm256_broadcast_ss(reinterpret_cast<const float *>(&c_general::signMaskFloat[1])); }
+
+    static inline __m256  CONST _mm256_set2power31_ps()    { return _mm256_broadcast_ss(&c_general::_2power31); }
+    static inline __m256i CONST _mm256_set2power31_epu32() { return _mm256_castps_si256(_mm256_broadcast_ss(reinterpret_cast<const float *>(&c_general::signMaskFloat[1]))); }
+
+    //X         static inline __m256i CONST _mm256_setmin_epi8 () { return _mm256_slli_epi8 (_mm256_setallone_si256(),  7); }
+    static inline __m128i CONST _mm_setmin_epi16() { return _mm_castps_si128(_mm_broadcast_ss(reinterpret_cast<const float *>(c_general::minShort))); }
+    static inline __m128i CONST _mm_setmin_epi32() { return _mm_castps_si128(_mm_broadcast_ss(reinterpret_cast<const float *>(&c_general::signMaskFloat[1]))); }
+    static inline __m256i CONST _mm256_setmin_epi16() { return _mm256_castps_si256(_mm256_broadcast_ss(reinterpret_cast<const float *>(c_general::minShort))); }
+    static inline __m256i CONST _mm256_setmin_epi32() { return _mm256_castps_si256(_mm256_broadcast_ss(reinterpret_cast<const float *>(&c_general::signMaskFloat[1]))); }
+
+#ifdef VC_REQUIRES_MACRO_FOR_IMMEDIATE_ARGUMENT
+#define _mm_extract_epu8 _mm_extract_epi8
+#define _mm_extract_epu16 _mm_extract_epi16
+#define _mm_extract_epu32 _mm_extract_epi32
+#else
+    static inline unsigned char INTRINSIC CONST _mm_extract_epu8(__m128i x, const int i) { return _mm_extract_epi8(x, i); }
+    static inline unsigned short INTRINSIC CONST _mm_extract_epu16(__m128i x, const int i) { return _mm_extract_epi16(x, i); }
+    static inline unsigned int INTRINSIC CONST _mm_extract_epu32(__m128i x, const int i) { return _mm_extract_epi32(x, i); }
+#endif
+
+    /////////////////////// COMPARE OPS ///////////////////////
+    static inline __m256d INTRINSIC CONST _mm256_cmpeq_pd   (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OQ); }
+    static inline __m256d INTRINSIC CONST _mm256_cmpneq_pd  (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_UQ); }
+    static inline __m256d INTRINSIC CONST _mm256_cmplt_pd   (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); }
+    static inline __m256d INTRINSIC CONST _mm256_cmpnlt_pd  (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); }
+    static inline __m256d INTRINSIC CONST _mm256_cmple_pd   (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); }
+    static inline __m256d INTRINSIC CONST _mm256_cmpnle_pd  (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); }
+    static inline __m256d INTRINSIC CONST _mm256_cmpord_pd  (__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_ORD_Q); }
+    static inline __m256d INTRINSIC CONST _mm256_cmpunord_pd(__m256d a, __m256d b) { return _mm256_cmp_pd(a, b, _CMP_UNORD_Q); }
+
+    static inline __m256  INTRINSIC CONST _mm256_cmpeq_ps   (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_EQ_OQ); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpneq_ps  (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_NEQ_UQ); }
+    static inline __m256  INTRINSIC CONST _mm256_cmplt_ps   (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_LT_OS); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpnlt_ps  (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_NLT_US); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpge_ps   (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_NLT_US); }
+    static inline __m256  INTRINSIC CONST _mm256_cmple_ps   (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_LE_OS); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpnle_ps  (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_NLE_US); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpgt_ps   (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_NLE_US); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpord_ps  (__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_ORD_Q); }
+    static inline __m256  INTRINSIC CONST _mm256_cmpunord_ps(__m256  a, __m256  b) { return _mm256_cmp_ps(a, b, _CMP_UNORD_Q); }
+
+    static inline __m128i _mm_cmplt_epu16(__m128i a, __m128i b) {
+        return _mm_cmplt_epi16(_mm_xor_si128(a, _mm_setmin_epi16()), _mm_xor_si128(b, _mm_setmin_epi16()));
+    }
+    static inline __m128i _mm_cmpgt_epu16(__m128i a, __m128i b) {
+        return _mm_cmpgt_epi16(_mm_xor_si128(a, _mm_setmin_epi16()), _mm_xor_si128(b, _mm_setmin_epi16()));
+    }
+
+    /////////////////////// INTEGER OPS ///////////////////////
+#define AVX_TO_SSE_2(name) \
+    static inline __m256i INTRINSIC CONST _mm256_##name(__m256i a0, __m256i b0) { \
+        __m128i a1 = _mm256_extractf128_si256(a0, 1); \
+        __m128i b1 = _mm256_extractf128_si256(b0, 1); \
+        __m128i r0 = _mm_##name(_mm256_castsi256_si128(a0), _mm256_castsi256_si128(b0)); \
+        __m128i r1 = _mm_##name(a1, b1); \
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1); \
+    }
+#define AVX_TO_SSE_2_si128_si256(name) \
+    static inline __m256i INTRINSIC CONST _mm256_##name##_si256(__m256i a0, __m256i b0) { \
+        __m128i a1 = _mm256_extractf128_si256(a0, 1); \
+        __m128i b1 = _mm256_extractf128_si256(b0, 1); \
+        __m128i r0 = _mm_##name##_si128(_mm256_castsi256_si128(a0), _mm256_castsi256_si128(b0)); \
+        __m128i r1 = _mm_##name##_si128(a1, b1); \
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1); \
+    }
+#define AVX_TO_SSE_1(name) \
+    static inline __m256i INTRINSIC CONST _mm256_##name(__m256i a0) { \
+        __m128i a1 = _mm256_extractf128_si256(a0, 1); \
+        __m128i r0 = _mm_##name(_mm256_castsi256_si128(a0)); \
+        __m128i r1 = _mm_##name(a1); \
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1); \
+    }
+#define AVX_TO_SSE_1i(name) \
+    static inline __m256i INTRINSIC CONST _mm256_##name(__m256i a0, const int i) { \
+        __m128i a1 = _mm256_extractf128_si256(a0, 1); \
+        __m128i r0 = _mm_##name(_mm256_castsi256_si128(a0), i); \
+        __m128i r1 = _mm_##name(a1, i); \
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1); \
+    }
+
+    AVX_TO_SSE_2(cmpeq_epi8)
+    AVX_TO_SSE_2(cmpeq_epi16)
+    AVX_TO_SSE_2(cmpeq_epi32)
+    AVX_TO_SSE_2(cmplt_epi8)
+    AVX_TO_SSE_2(cmplt_epi16)
+    AVX_TO_SSE_2(cmplt_epi32)
+    AVX_TO_SSE_2(cmpgt_epi8)
+    AVX_TO_SSE_2(cmpgt_epi16)
+    AVX_TO_SSE_2(cmpgt_epi32)
+
+#ifndef VC_ICC
+    // ICC ships the Integer intrinsics inside the AVX1 header these days.
+
+#ifdef VC_REQUIRES_MACRO_FOR_IMMEDIATE_ARGUMENT
+#   define _mm256_srli_si256(a, i) \
+        _mm256_insertf128_si256( \
+                _mm256_castsi128_si256(_mm_srli_si128(_mm256_castsi256_si128((a)), i)), \
+                _mm_srli_si128(_mm256_extractf128_si256((a), 1), i), 1);
+#   define _mm256_slli_si256(a, i) \
+        _mm256_insertf128_si256( \
+                _mm256_castsi128_si256( _mm_slli_si128(_mm256_castsi256_si128((a)), i)), \
+                _mm_slli_si128(_mm256_extractf128_si256((a), 1), i), 1);
+#else
+    static inline __m256i INTRINSIC CONST _mm256_srli_si256(__m256i a0, const int i) {
+        const __m128i r0 = _mm_srli_si128(_mm256_castsi256_si128(a0), i);
+        const __m128i r1 = _mm_srli_si128(_mm256_extractf128_si256(a0, 1), i);
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1);
+    }
+    static inline __m256i INTRINSIC CONST _mm256_slli_si256(__m256i a0, const int i) {
+        const __m128i r0 = _mm_slli_si128(_mm256_castsi256_si128(a0), i);
+        const __m128i r1 = _mm_slli_si128(_mm256_extractf128_si256(a0, 1), i);
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1);
+    }
+#endif
+
+    static inline __m256i INTRINSIC CONST _mm256_and_si256(__m256i x, __m256i y) {
+        return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(x), _mm256_castsi256_ps(y)));
+    }
+    static inline __m256i INTRINSIC CONST _mm256_andnot_si256(__m256i x, __m256i y) {
+        return _mm256_castps_si256(_mm256_andnot_ps(_mm256_castsi256_ps(x), _mm256_castsi256_ps(y)));
+    }
+    static inline __m256i INTRINSIC CONST _mm256_or_si256(__m256i x, __m256i y) {
+        return _mm256_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(x), _mm256_castsi256_ps(y)));
+    }
+    static inline __m256i INTRINSIC CONST _mm256_xor_si256(__m256i x, __m256i y) {
+        return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(x), _mm256_castsi256_ps(y)));
+    }
+
+    AVX_TO_SSE_2(packs_epi16)
+    AVX_TO_SSE_2(packs_epi32)
+    AVX_TO_SSE_2(packus_epi16)
+    AVX_TO_SSE_2(unpackhi_epi8)
+    AVX_TO_SSE_2(unpackhi_epi16)
+    AVX_TO_SSE_2(unpackhi_epi32)
+    AVX_TO_SSE_2(unpackhi_epi64)
+    AVX_TO_SSE_2(unpacklo_epi8)
+    AVX_TO_SSE_2(unpacklo_epi16)
+    AVX_TO_SSE_2(unpacklo_epi32)
+    AVX_TO_SSE_2(unpacklo_epi64)
+    AVX_TO_SSE_2(add_epi8)
+    AVX_TO_SSE_2(add_epi16)
+    AVX_TO_SSE_2(add_epi32)
+    AVX_TO_SSE_2(add_epi64)
+    AVX_TO_SSE_2(adds_epi8)
+    AVX_TO_SSE_2(adds_epi16)
+    AVX_TO_SSE_2(adds_epu8)
+    AVX_TO_SSE_2(adds_epu16)
+    AVX_TO_SSE_2(sub_epi8)
+    AVX_TO_SSE_2(sub_epi16)
+    AVX_TO_SSE_2(sub_epi32)
+    AVX_TO_SSE_2(sub_epi64)
+    AVX_TO_SSE_2(subs_epi8)
+    AVX_TO_SSE_2(subs_epi16)
+    AVX_TO_SSE_2(subs_epu8)
+    AVX_TO_SSE_2(subs_epu16)
+    AVX_TO_SSE_2(madd_epi16)
+    AVX_TO_SSE_2(mulhi_epi16)
+    AVX_TO_SSE_2(mullo_epi16)
+    AVX_TO_SSE_2(mul_epu32)
+    AVX_TO_SSE_1i(slli_epi16)
+    AVX_TO_SSE_1i(slli_epi32)
+    AVX_TO_SSE_1i(slli_epi64)
+    AVX_TO_SSE_1i(srai_epi16)
+    AVX_TO_SSE_1i(srai_epi32)
+    AVX_TO_SSE_1i(srli_epi16)
+    AVX_TO_SSE_1i(srli_epi32)
+    AVX_TO_SSE_1i(srli_epi64)
+    AVX_TO_SSE_2(sll_epi16)
+    AVX_TO_SSE_2(sll_epi32)
+    AVX_TO_SSE_2(sll_epi64)
+    AVX_TO_SSE_2(sra_epi16)
+    AVX_TO_SSE_2(sra_epi32)
+    AVX_TO_SSE_2(srl_epi16)
+    AVX_TO_SSE_2(srl_epi32)
+    AVX_TO_SSE_2(srl_epi64)
+    AVX_TO_SSE_2(max_epi16)
+    AVX_TO_SSE_2(max_epu8)
+    AVX_TO_SSE_2(min_epi16)
+    AVX_TO_SSE_2(min_epu8)
+    inline int INTRINSIC CONST _mm256_movemask_epi8(__m256i a0)
+    {
+        __m128i a1 = _mm256_extractf128_si256(a0, 1);
+        return (_mm_movemask_epi8(a1) << 16) | _mm_movemask_epi8(_mm256_castsi256_si128(a0));
+    }
+    AVX_TO_SSE_2(mulhi_epu16)
+    // shufflehi_epi16
+    // shufflelo_epi16 (__m128i __A, const int __mask)
+    // shuffle_epi32 (__m128i __A, const int __mask)
+    // maskmoveu_si128 (__m128i __A, __m128i __B, char *__C)
+    AVX_TO_SSE_2(avg_epu8)
+    AVX_TO_SSE_2(avg_epu16)
+    AVX_TO_SSE_2(sad_epu8)
+    // stream_si32 (int *__A, int __B)
+    // stream_si128 (__m128i *__A, __m128i __B)
+    // cvtsi32_si128 (int __A)
+    // cvtsi64_si128 (long long __A)
+    // cvtsi64x_si128 (long long __A)
+    AVX_TO_SSE_2(hadd_epi16)
+    AVX_TO_SSE_2(hadd_epi32)
+    AVX_TO_SSE_2(hadds_epi16)
+    AVX_TO_SSE_2(hsub_epi16)
+    AVX_TO_SSE_2(hsub_epi32)
+    AVX_TO_SSE_2(hsubs_epi16)
+    AVX_TO_SSE_2(maddubs_epi16)
+    AVX_TO_SSE_2(mulhrs_epi16)
+    AVX_TO_SSE_2(shuffle_epi8)
+    AVX_TO_SSE_2(sign_epi8)
+    AVX_TO_SSE_2(sign_epi16)
+    AVX_TO_SSE_2(sign_epi32)
+    // alignr_epi8(__m128i __X, __m128i __Y, const int __N)
+    AVX_TO_SSE_1(abs_epi8)
+    AVX_TO_SSE_1(abs_epi16)
+    AVX_TO_SSE_1(abs_epi32)
+#if !defined(VC_REQUIRES_MACRO_FOR_IMMEDIATE_ARGUMENT)
+    __m256i inline INTRINSIC CONST _mm256_blend_epi16(__m256i a0, __m256i b0, const int m) {
+        __m128i a1 = _mm256_extractf128_si256(a0, 1);
+        __m128i b1 = _mm256_extractf128_si256(b0, 1);
+        __m128i r0 = _mm_blend_epi16(_mm256_castsi256_si128(a0), _mm256_castsi256_si128(b0), m & 0xff);
+        __m128i r1 = _mm_blend_epi16(a1, b1, m >> 8);
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1);
+    }
+#else
+#   define _mm256_blend_epi16(a0, b0, m) \
+    _mm256_insertf128_si256( \
+            _mm256_castsi128_si256( \
+                _mm_blend_epi16( \
+                    _mm256_castsi256_si128(a0), _mm256_castsi256_si128(b0), m & 0xff)), \
+            _mm_blend_epi16(_mm256_extractf128_si256(a0, 1), _mm256_extractf128_si256(b0, 1), m >> 8);, 1)
+#endif
+    inline __m256i INTRINSIC CONST _mm256_blendv_epi8(__m256i a0, __m256i b0, __m256i m0) {
+        __m128i a1 = _mm256_extractf128_si256(a0, 1);
+        __m128i b1 = _mm256_extractf128_si256(b0, 1);
+        __m128i m1 = _mm256_extractf128_si256(m0, 1);
+        __m128i r0 = _mm_blendv_epi8(_mm256_castsi256_si128(a0), _mm256_castsi256_si128(b0), _mm256_castsi256_si128(m0));
+        __m128i r1 = _mm_blendv_epi8(a1, b1, m1);
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(r0), r1, 1);
+    }
+    AVX_TO_SSE_2(cmpeq_epi64)
+    AVX_TO_SSE_2(min_epi8)
+    AVX_TO_SSE_2(max_epi8)
+    AVX_TO_SSE_2(min_epu16)
+    AVX_TO_SSE_2(max_epu16)
+    AVX_TO_SSE_2(min_epi32)
+    AVX_TO_SSE_2(max_epi32)
+    AVX_TO_SSE_2(min_epu32)
+    AVX_TO_SSE_2(max_epu32)
+    AVX_TO_SSE_2(mullo_epi32)
+    AVX_TO_SSE_2(mul_epi32)
+#if !defined(VC_CLANG) || VC_CLANG > 0x30100
+    // clang is missing _mm_minpos_epu16 from smmintrin.h
+    // http://llvm.org/bugs/show_bug.cgi?id=12399
+    AVX_TO_SSE_1(minpos_epu16)
+#endif
+    AVX_TO_SSE_1(cvtepi8_epi32)
+    AVX_TO_SSE_1(cvtepi16_epi32)
+    AVX_TO_SSE_1(cvtepi8_epi64)
+    AVX_TO_SSE_1(cvtepi32_epi64)
+    AVX_TO_SSE_1(cvtepi16_epi64)
+    AVX_TO_SSE_1(cvtepi8_epi16)
+    AVX_TO_SSE_1(cvtepu8_epi32)
+    AVX_TO_SSE_1(cvtepu16_epi32)
+    AVX_TO_SSE_1(cvtepu8_epi64)
+    AVX_TO_SSE_1(cvtepu32_epi64)
+    AVX_TO_SSE_1(cvtepu16_epi64)
+    AVX_TO_SSE_1(cvtepu8_epi16)
+    AVX_TO_SSE_2(packus_epi32)
+    // mpsadbw_epu8 (__m128i __X, __m128i __Y, const int __M)
+    // stream_load_si128 (__m128i *__X)
+    AVX_TO_SSE_2(cmpgt_epi64)
+#endif
+
+//X     static inline __m256i _mm256_cmplt_epu8 (__m256i a, __m256i b) { return _mm256_cmplt_epi8 (
+//X             _mm256_xor_si256(a, _mm256_setmin_epi8 ()), _mm256_xor_si256(b, _mm256_setmin_epi8 ())); }
+//X     static inline __m256i _mm256_cmpgt_epu8 (__m256i a, __m256i b) { return _mm256_cmpgt_epi8 (
+//X             _mm256_xor_si256(a, _mm256_setmin_epi8 ()), _mm256_xor_si256(b, _mm256_setmin_epi8 ())); }
+    static inline __m256i CONST _mm256_cmplt_epu32(__m256i a, __m256i b) {
+        a = _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(_mm256_setmin_epi32())));
+        b = _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(_mm256_setmin_epi32())));
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(
+                    _mm_cmplt_epi32(_mm256_castsi256_si128(a), _mm256_castsi256_si128(b))),
+                _mm_cmplt_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1)), 1);
+    }
+    static inline __m256i CONST _mm256_cmpgt_epu32(__m256i a, __m256i b) {
+        a = _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(_mm256_setmin_epi32())));
+        b = _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(_mm256_setmin_epi32())));
+        return _mm256_insertf128_si256(_mm256_castsi128_si256(
+                    _mm_cmpgt_epi32(_mm256_castsi256_si128(a), _mm256_castsi256_si128(b))),
+                _mm_cmpgt_epi32(_mm256_extractf128_si256(a, 1), _mm256_extractf128_si256(b, 1)), 1);
+    }
+
+        static inline void INTRINSIC _mm256_maskstore(float *mem, const __m256 mask, const __m256 v) {
+#ifndef VC_MM256_MASKSTORE_WRONG_MASK_TYPE
+            _mm256_maskstore_ps(mem, _mm256_castps_si256(mask), v);
+#else
+            _mm256_maskstore_ps(mem, mask, v);
+#endif
+        }
+        static inline void INTRINSIC _mm256_maskstore(double *mem, const __m256d mask, const __m256d v) {
+#ifndef VC_MM256_MASKSTORE_WRONG_MASK_TYPE
+            _mm256_maskstore_pd(mem, _mm256_castpd_si256(mask), v);
+#else
+            _mm256_maskstore_pd(mem, mask, v);
+#endif
+        }
+        static inline void INTRINSIC _mm256_maskstore(int *mem, const __m256i mask, const __m256i v) {
+#ifndef VC_MM256_MASKSTORE_WRONG_MASK_TYPE
+            _mm256_maskstore_ps(reinterpret_cast<float *>(mem), mask, _mm256_castsi256_ps(v));
+#else
+            _mm256_maskstore_ps(reinterpret_cast<float *>(mem), _mm256_castsi256_ps(mask), _mm256_castsi256_ps(v));
+#endif
+        }
+        static inline void INTRINSIC _mm256_maskstore(unsigned int *mem, const __m256i mask, const __m256i v) {
+            _mm256_maskstore(reinterpret_cast<int *>(mem), mask, v);
+        }
+} // namespace AVX
+} // namespace Vc
+
+#include "shuffle.h"
+
+#endif // VC_AVX_INTRINSICS_H
diff --git a/Vc/include/Vc/avx/limits.h b/Vc/include/Vc/avx/limits.h
new file mode 100644 (file)
index 0000000..80722da
--- /dev/null
@@ -0,0 +1,49 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_LIMITS_H
+#define VC_AVX_LIMITS_H
+
+#include "intrinsics.h"
+#include "types.h"
+
+namespace std
+{
+#define _VC_NUM_LIM(T, _max, _min) \
+template<> struct numeric_limits<Vc::AVX::Vector<T> > : public numeric_limits<T> \
+{ \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> max()           _VC_NOEXCEPT { return _max; } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> min()           _VC_NOEXCEPT { return _min; } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> lowest()        _VC_NOEXCEPT { return min(); } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> epsilon()       _VC_NOEXCEPT { return Vc::AVX::Vector<T>::Zero(); } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> round_error()   _VC_NOEXCEPT { return Vc::AVX::Vector<T>::Zero(); } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> infinity()      _VC_NOEXCEPT { return Vc::AVX::Vector<T>::Zero(); } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> quiet_NaN()     _VC_NOEXCEPT { return Vc::AVX::Vector<T>::Zero(); } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> signaling_NaN() _VC_NOEXCEPT { return Vc::AVX::Vector<T>::Zero(); } \
+    static inline INTRINSIC CONST Vc::AVX::Vector<T> denorm_min()    _VC_NOEXCEPT { return Vc::AVX::Vector<T>::Zero(); } \
+}
+_VC_NUM_LIM(unsigned short, Vc::AVX::_mm_setallone_si128(), _mm_setzero_si128());
+_VC_NUM_LIM(         short, _mm_srli_epi16(Vc::AVX::_mm_setallone_si128(), 1), Vc::AVX::_mm_setmin_epi16());
+_VC_NUM_LIM(  unsigned int, Vc::AVX::_mm256_setallone_si256(), _mm256_setzero_si256());
+_VC_NUM_LIM(           int, Vc::AVX::_mm256_srli_epi32(Vc::AVX::_mm256_setallone_si256(), 1), Vc::AVX::_mm256_setmin_epi32());
+#undef _VC_NUM_LIM
+
+} // namespace std
+
+#endif // VC_AVX_LIMITS_H
diff --git a/Vc/include/Vc/avx/macros.h b/Vc/include/Vc/avx/macros.h
new file mode 100644 (file)
index 0000000..17d10f6
--- /dev/null
@@ -0,0 +1,38 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "../common/macros.h"
+
+#ifndef VC_AVX_MACROS_H
+#define VC_AVX_MACROS_H
+#undef VC_AVX_UNDOMACROS_H
+
+#ifndef _M256
+# define _M256 __m256
+#endif
+
+#ifndef _M256I
+# define _M256I __m256i
+#endif
+
+#ifndef _M256D
+# define _M256D __m256d
+#endif
+
+#endif // VC_AVX_MACROS_H
diff --git a/Vc/include/Vc/avx/mask.h b/Vc/include/Vc/avx/mask.h
new file mode 100644 (file)
index 0000000..4d678ea
--- /dev/null
@@ -0,0 +1,195 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_MASK_H
+#define VC_AVX_MASK_H
+
+#include "intrinsics.h"
+#include "../common/bitscanintrinsics.h"
+
+namespace Vc
+{
+namespace AVX
+{
+
+template<unsigned int VectorSize> class Mask<VectorSize, 32u>
+{
+    friend class Mask<4u, 32u>; // double_v
+    friend class Mask<8u, 32u>; // float_v, (u)int_v
+    friend class Mask<8u, 16u>; // (u)short_v
+    friend class Mask<16u, 16u>; // (u)char_v
+    public:
+        FREE_STORE_OPERATORS_ALIGNED(32)
+
+        // abstracts the way Masks are passed to functions, it can easily be changed to const ref here
+#if defined VC_MSVC && defined _WIN32
+        typedef const Mask<VectorSize, 32u> &AsArg;
+#else
+        typedef Mask<VectorSize, 32u> AsArg;
+#endif
+
+        inline Mask() {}
+        inline Mask(const __m256  &x) : k(x) {}
+        inline Mask(const __m256d &x) : k(_mm256_castpd_ps(x)) {}
+        inline Mask(const __m256i &x) : k(_mm256_castsi256_ps(x)) {}
+        inline explicit Mask(VectorSpecialInitializerZero::ZEnum) : k(_mm256_setzero_ps()) {}
+        inline explicit Mask(VectorSpecialInitializerOne::OEnum) : k(_mm256_setallone_ps()) {}
+        inline explicit Mask(bool b) : k(b ? _mm256_setallone_ps() : _mm256_setzero_ps()) {}
+        inline Mask(const Mask &rhs) : k(rhs.k) {}
+        inline Mask(const Mask<VectorSize, 16u> &rhs) : k(avx_cast<__m256>(concat(
+                        _mm_unpacklo_epi16(rhs.dataI(), rhs.dataI()),
+                        _mm_unpackhi_epi16(rhs.dataI(), rhs.dataI())))) {}
+        inline Mask(const Mask<VectorSize * 2, 32u> &m);
+        inline Mask(const Mask<VectorSize / 2, 32u> &m);
+
+        inline bool operator==(const Mask &rhs) const { return 0 != _mm256_testc_ps(k, rhs.k); }
+        inline bool operator!=(const Mask &rhs) const { return 0 == _mm256_testc_ps(k, rhs.k); }
+
+        inline Mask operator&&(const Mask &rhs) const { return _mm256_and_ps(k, rhs.k); }
+        inline Mask operator& (const Mask &rhs) const { return _mm256_and_ps(k, rhs.k); }
+        inline Mask operator||(const Mask &rhs) const { return _mm256_or_ps (k, rhs.k); }
+        inline Mask operator| (const Mask &rhs) const { return _mm256_or_ps (k, rhs.k); }
+        inline Mask operator^ (const Mask &rhs) const { return _mm256_xor_ps(k, rhs.k); }
+        inline Mask operator!() const { return _mm256_andnot_ps(data(), _mm256_setallone_ps()); }
+
+        inline Mask &operator&=(const Mask &rhs) { k = _mm256_and_ps(k, rhs.k); return *this; }
+        inline Mask &operator|=(const Mask &rhs) { k = _mm256_or_ps (k, rhs.k); return *this; }
+
+        // no need for expression template optimizations because cmp(n)eq for floats are not bitwise
+        // compares
+        inline bool isFull () const { return 0 != _mm256_testc_ps(k, _mm256_setallone_ps()); }
+        inline bool isEmpty() const { return 0 != _mm256_testz_ps(k, k); }
+        inline bool isMix  () const { return 0 != _mm256_testnzc_ps(k, _mm256_setallone_ps()); }
+
+#ifndef VC_NO_AUTOMATIC_BOOL_FROM_MASK
+        inline operator bool() const { return isFull(); }
+#endif
+
+        inline int CONST_L shiftMask() const CONST_R;
+        int CONST_L toInt() const CONST_R;
+
+        inline _M256  data () const { return k; }
+        inline _M256I dataI() const { return _mm256_castps_si256(k); }
+        inline _M256D dataD() const { return _mm256_castps_pd(k); }
+
+        bool operator[](int index) const;
+
+        int count() const;
+        int firstOne() const;
+
+    private:
+        _M256 k;
+};
+
+template<unsigned int VectorSize> class Mask<VectorSize, 16u>
+{
+    friend class Mask<4u, 32u>; // double_v
+    friend class Mask<8u, 32u>; // float_v, (u)int_v
+    friend class Mask<8u, 16u>; // (u)short_v
+    friend class Mask<16u, 16u>; // (u)char_v
+    public:
+        FREE_STORE_OPERATORS_ALIGNED(16)
+
+        // abstracts the way Masks are passed to functions, it can easily be changed to const ref here
+#if defined VC_MSVC && defined _WIN32
+        typedef const Mask<VectorSize, 16u> &AsArg;
+#else
+        typedef Mask<VectorSize, 16u> AsArg;
+#endif
+
+        inline Mask() {}
+        inline Mask(const __m128  &x) : k(x) {}
+        inline Mask(const __m128d &x) : k(_mm_castpd_ps(x)) {}
+        inline Mask(const __m128i &x) : k(_mm_castsi128_ps(x)) {}
+        inline explicit Mask(VectorSpecialInitializerZero::ZEnum) : k(_mm_setzero_ps()) {}
+        inline explicit Mask(VectorSpecialInitializerOne::OEnum) : k(_mm_setallone_ps()) {}
+        inline explicit Mask(bool b) : k(b ? _mm_setallone_ps() : _mm_setzero_ps()) {}
+        inline Mask(const Mask &rhs) : k(rhs.k) {}
+        inline Mask(const Mask<VectorSize, 32u> &rhs) : k(avx_cast<__m128>(
+                _mm_packs_epi32(avx_cast<__m128i>(rhs.data()), _mm256_extractf128_si256(rhs.dataI(), 1)))) {}
+        inline Mask(const Mask<VectorSize / 2, 16u> *a) : k(avx_cast<__m128>(
+                _mm_packs_epi16(a[0].dataI(), a[1].dataI()))) {}
+
+        inline bool operator==(const Mask &rhs) const { return 0 != _mm_testc_si128(dataI(), rhs.dataI()); }
+        inline bool operator!=(const Mask &rhs) const { return 0 == _mm_testc_si128(dataI(), rhs.dataI()); }
+
+        inline Mask operator&&(const Mask &rhs) const { return _mm_and_ps(k, rhs.k); }
+        inline Mask operator& (const Mask &rhs) const { return _mm_and_ps(k, rhs.k); }
+        inline Mask operator||(const Mask &rhs) const { return _mm_or_ps (k, rhs.k); }
+        inline Mask operator| (const Mask &rhs) const { return _mm_or_ps (k, rhs.k); }
+        inline Mask operator^ (const Mask &rhs) const { return _mm_xor_ps(k, rhs.k); }
+        inline Mask operator!() const { return _mm_andnot_ps(data(), _mm_setallone_ps()); }
+
+        inline Mask &operator&=(const Mask &rhs) { k = _mm_and_ps(k, rhs.k); return *this; }
+        inline Mask &operator|=(const Mask &rhs) { k = _mm_or_ps (k, rhs.k); return *this; }
+
+        // TODO: use expression templates to optimize (v1 == v2).isFull() and friends
+        inline bool isFull () const { return 0 != _mm_testc_si128(dataI(), _mm_setallone_si128()); }
+        inline bool isEmpty() const { return 0 != _mm_testz_si128(dataI(), dataI()); }
+        inline bool isMix  () const { return 0 != _mm_testnzc_si128(dataI(), _mm_setallone_si128()); }
+
+#ifndef VC_NO_AUTOMATIC_BOOL_FROM_MASK
+        inline operator bool() const { return isFull(); }
+#endif
+
+        inline int CONST_L shiftMask() const CONST_R;
+        int CONST_L toInt() const CONST_R;
+
+        inline __m128  data () const { return k; }
+        inline __m128i dataI() const { return avx_cast<__m128i>(k); }
+        inline __m128d dataD() const { return avx_cast<__m128d>(k); }
+
+        bool operator[](int index) const;
+
+        int count() const;
+        int firstOne() const;
+
+    private:
+        __m128 k;
+};
+
+struct ForeachHelper
+{
+    size_t mask;
+    bool brk;
+    inline ForeachHelper(size_t _mask) : mask(_mask), brk(false) {}
+    inline bool outer() const { return mask != 0; }
+    inline bool inner() { return (brk = !brk); }
+    inline size_t next() {
+#ifdef VC_GNU_ASM
+        const size_t bit = __builtin_ctzl(mask);
+        __asm__("btr %1,%0" : "+r"(mask) : "r"(bit));
+#else
+        const size_t bit = _bit_scan_forward(mask);
+        mask &= ~(1 << bit);
+#endif
+        return bit;
+    }
+};
+
+#define Vc_foreach_bit(_it_, _mask_) \
+    for (Vc::AVX::ForeachHelper _Vc_foreach_bit_helper((_mask_).toInt()); _Vc_foreach_bit_helper.outer(); ) \
+        for (_it_ = _Vc_foreach_bit_helper.next(); _Vc_foreach_bit_helper.inner(); )
+
+} // namespace AVX
+} // namespace Vc
+
+#include "mask.tcc"
+
+#endif // VC_AVX_MASK_H
diff --git a/Vc/include/Vc/avx/mask.tcc b/Vc/include/Vc/avx/mask.tcc
new file mode 100644 (file)
index 0000000..ce09174
--- /dev/null
@@ -0,0 +1,63 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+namespace Vc
+{
+namespace AVX
+{
+
+template<> inline Mask<4, 32>::Mask(const Mask<8, 32> &m)
+    : k(concat(_mm_unpacklo_ps(lo128(m.data()), lo128(m.data())),
+                _mm_unpackhi_ps(lo128(m.data()), lo128(m.data()))))
+{
+}
+
+template<> inline Mask<8, 32>::Mask(const Mask<4, 32> &m)
+    // aabb ccdd -> abcd 0000
+    : k(concat(Mem::shuffle<X0, X2, Y0, Y2>(lo128(m.data()), hi128(m.data())),
+                _mm_setzero_ps()))
+{
+}
+
+template<unsigned int Size> inline int Mask<Size, 32u>::shiftMask() const
+{
+    return _mm256_movemask_epi8(dataI());
+}
+template<unsigned int Size> inline int Mask<Size, 16u>::shiftMask() const
+{
+    return _mm_movemask_epi8(dataI());
+}
+
+template<> inline int Mask< 4, 32>::toInt() const { return _mm256_movemask_pd(dataD()); }
+template<> inline int Mask< 8, 32>::toInt() const { return _mm256_movemask_ps(data ()); }
+template<> inline int Mask< 8, 16>::toInt() const { return _mm_movemask_epi8(_mm_packs_epi16(dataI(), _mm_setzero_si128())); }
+template<> inline int Mask<16, 16>::toInt() const { return _mm_movemask_epi8(dataI()); }
+
+template<> inline bool Mask< 4, 32>::operator[](int index) const { return toInt() & (1 << index); }
+template<> inline bool Mask< 8, 32>::operator[](int index) const { return toInt() & (1 << index); }
+template<> inline bool Mask< 8, 16>::operator[](int index) const { return shiftMask() & (1 << 2 * index); }
+template<> inline bool Mask<16, 16>::operator[](int index) const { return toInt() & (1 << index); }
+
+template<unsigned int Size> inline int Mask<Size, 32u>::count() const { return _mm_popcnt_u32(toInt()); }
+template<unsigned int Size> inline int Mask<Size, 16u>::count() const { return _mm_popcnt_u32(toInt()); }
+template<unsigned int Size> inline int Mask<Size, 32u>::firstOne() const { return _bit_scan_forward(toInt()); }
+template<unsigned int Size> inline int Mask<Size, 16u>::firstOne() const { return _bit_scan_forward(toInt()); }
+
+} // namespace AVX
+} // namespace Vc
diff --git a/Vc/include/Vc/avx/math.h b/Vc/include/Vc/avx/math.h
new file mode 100644 (file)
index 0000000..be7d1ba
--- /dev/null
@@ -0,0 +1,113 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_MATH_H
+#define VC_AVX_MATH_H
+
+#include "const.h"
+#include "limits.h"
+#include "macros.h"
+
+namespace Vc
+{
+namespace AVX
+{
+    /**
+     * splits \p v into exponent and mantissa, the sign is kept with the mantissa
+     *
+     * The return value will be in the range [0.5, 1.0[
+     * The \p e value will be an integer defining the power-of-two exponent
+     */
+    inline double_v frexp(double_v::AsArg v, int_v *e) {
+        const __m256d exponentBits = Const<double>::exponentMask().dataD();
+        const __m256d exponentPart = _mm256_and_pd(v.data(), exponentBits);
+        e->data() = _mm256_sub_epi32(_mm256_srli_epi64(avx_cast<__m256i>(exponentPart), 52), _mm256_set1_epi32(0x3fe));
+        const __m256d exponentMaximized = _mm256_or_pd(v.data(), exponentBits);
+        double_v ret = _mm256_and_pd(exponentMaximized, _mm256_broadcast_sd(reinterpret_cast<const double *>(&c_general::frexpMask)));
+        double_m zeroMask = v == double_v::Zero();
+        ret(isnan(v) || !isfinite(v) || zeroMask) = v;
+        e->setZero(zeroMask.data());
+        return ret;
+    }
+    inline float_v frexp(float_v::AsArg v, int_v *e) {
+        const __m256 exponentBits = Const<float>::exponentMask().data();
+        const __m256 exponentPart = _mm256_and_ps(v.data(), exponentBits);
+        e->data() = _mm256_sub_epi32(_mm256_srli_epi32(avx_cast<__m256i>(exponentPart), 23), _mm256_set1_epi32(0x7e));
+        const __m256 exponentMaximized = _mm256_or_ps(v.data(), exponentBits);
+        float_v ret = _mm256_and_ps(exponentMaximized, avx_cast<__m256>(_mm256_set1_epi32(0xbf7fffffu)));
+        ret(isnan(v) || !isfinite(v) || v == float_v::Zero()) = v;
+        e->setZero(v == float_v::Zero());
+        return ret;
+    }
+    inline sfloat_v frexp(sfloat_v::AsArg v, short_v *e) {
+        const __m256 exponentBits = Const<float>::exponentMask().data();
+        const __m256 exponentPart = _mm256_and_ps(v.data(), exponentBits);
+        e->data() = _mm_sub_epi16(_mm_packs_epi32(_mm_srli_epi32(avx_cast<__m128i>(exponentPart), 23),
+                    _mm_srli_epi32(avx_cast<__m128i>(hi128(exponentPart)), 23)), _mm_set1_epi16(0x7e));
+        const __m256 exponentMaximized = _mm256_or_ps(v.data(), exponentBits);
+        sfloat_v ret = _mm256_and_ps(exponentMaximized, avx_cast<__m256>(_mm256_set1_epi32(0xbf7fffffu)));
+        ret(isnan(v) || !isfinite(v) || v == sfloat_v::Zero()) = v;
+        e->setZero(v == sfloat_v::Zero());
+        return ret;
+    }
+
+    /*             -> x * 2^e
+     * x == NaN    -> NaN
+     * x == (-)inf -> (-)inf
+     */
+    inline double_v ldexp(double_v::AsArg v, int_v::AsArg _e) {
+        int_v e = _e;
+        e.setZero((v == double_v::Zero()).dataI());
+        const __m256i exponentBits = _mm256_slli_epi64(e.data(), 52);
+        return avx_cast<__m256d>(_mm256_add_epi64(avx_cast<__m256i>(v.data()), exponentBits));
+    }
+    inline float_v ldexp(float_v::AsArg v, int_v::AsArg _e) {
+        int_v e = _e;
+        e.setZero(static_cast<int_m>(v == float_v::Zero()));
+        return (v.reinterpretCast<int_v>() + (e << 23)).reinterpretCast<float_v>();
+    }
+    inline sfloat_v ldexp(sfloat_v::AsArg v, short_v::AsArg _e) {
+        short_v e = _e;
+        e.setZero(static_cast<short_m>(v == sfloat_v::Zero()));
+        e = e << (23 - 16);
+        const __m256i exponentBits = concat(_mm_unpacklo_epi16(_mm_setzero_si128(), e.data()),
+                _mm_unpackhi_epi16(_mm_setzero_si128(), e.data()));
+        return (v.reinterpretCast<int_v>() + int_v(exponentBits)).reinterpretCast<sfloat_v>();
+    }
+
+    static inline float_v floor(float_v::AsArg v) { return _mm256_floor_ps(v.data()); }
+    static inline sfloat_v floor(sfloat_v::AsArg v) { return _mm256_floor_ps(v.data()); }
+    static inline double_v floor(double_v::AsArg v) { return _mm256_floor_pd(v.data()); }
+
+    static inline float_v ceil(float_v::AsArg v) { return _mm256_ceil_ps(v.data()); }
+    static inline sfloat_v ceil(sfloat_v::AsArg v) { return _mm256_ceil_ps(v.data()); }
+    static inline double_v ceil(double_v::AsArg v) { return _mm256_ceil_pd(v.data()); }
+} // namespace AVX
+} // namespace Vc
+
+#include "undomacros.h"
+#define VC__USE_NAMESPACE AVX
+#include "../common/trigonometric.h"
+#define VC__USE_NAMESPACE AVX
+#include "../common/logarithm.h"
+#define VC__USE_NAMESPACE AVX
+#include "../common/exponential.h"
+#undef VC__USE_NAMESPACE
+
+#endif // VC_AVX_MATH_H
diff --git a/Vc/include/Vc/avx/prefetches.tcc b/Vc/include/Vc/avx/prefetches.tcc
new file mode 100644 (file)
index 0000000..3a178a8
--- /dev/null
@@ -0,0 +1,56 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010, 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_PREFETCHES_TCC
+#define VC_AVX_PREFETCHES_TCC
+
+namespace Vc
+{
+namespace Internal
+{
+
+inline ALWAYS_INLINE void HelperImpl<Vc::AVXImpl>::prefetchForOneRead(const void *addr)
+{
+    _mm_prefetch(static_cast<char *>(const_cast<void *>(addr)), _MM_HINT_NTA);
+}
+inline ALWAYS_INLINE void HelperImpl<Vc::AVXImpl>::prefetchClose(const void *addr)
+{
+    _mm_prefetch(static_cast<char *>(const_cast<void *>(addr)), _MM_HINT_T0);
+}
+inline ALWAYS_INLINE void HelperImpl<Vc::AVXImpl>::prefetchMid(const void *addr)
+{
+    _mm_prefetch(static_cast<char *>(const_cast<void *>(addr)), _MM_HINT_T1);
+}
+inline ALWAYS_INLINE void HelperImpl<Vc::AVXImpl>::prefetchFar(const void *addr)
+{
+    _mm_prefetch(static_cast<char *>(const_cast<void *>(addr)), _MM_HINT_T2);
+}
+inline ALWAYS_INLINE void HelperImpl<Vc::AVXImpl>::prefetchForModify(const void *addr)
+{
+#ifdef __3dNOW__
+    _m_prefetchw(const_cast<void *>(addr));
+#else
+    _mm_prefetch(static_cast<char *>(const_cast<void *>(addr)), _MM_HINT_T0);
+#endif
+}
+
+} // namespace Internal
+} // namespace Vc
+
+#endif // VC_AVX_PREFETCHES_TCC
diff --git a/Vc/include/Vc/avx/shuffle.h b/Vc/include/Vc/avx/shuffle.h
new file mode 100644 (file)
index 0000000..b7e8287
--- /dev/null
@@ -0,0 +1,208 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_SHUFFLE_H
+#define VC_AVX_SHUFFLE_H
+
+#include "../sse/shuffle.h"
+
+namespace Vc
+{
+    namespace Mem
+    {
+        template<VecPos L, VecPos H> static inline __m256 ALWAYS_INLINE CONST shuffle128(__m256 x, __m256 y) {
+            VC_STATIC_ASSERT(L >= X0 && H >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(L <= Y1 && H <= Y1, Incorrect_Range);
+            return _mm256_permute2f128_ps(x, y, (L < Y0 ? L : L - Y0 + 2) + (H < Y0 ? H : H - Y0 + 2) * (1 << 4));
+        }
+        template<VecPos L, VecPos H> static inline __m256i ALWAYS_INLINE CONST shuffle128(__m256i x, __m256i y) {
+            VC_STATIC_ASSERT(L >= X0 && H >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(L <= Y1 && H <= Y1, Incorrect_Range);
+            return _mm256_permute2f128_si256(x, y, (L < Y0 ? L : L - Y0 + 2) + (H < Y0 ? H : H - Y0 + 2) * (1 << 4));
+        }
+        template<VecPos L, VecPos H> static inline __m256d ALWAYS_INLINE CONST shuffle128(__m256d x, __m256d y) {
+            VC_STATIC_ASSERT(L >= X0 && H >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(L <= Y1 && H <= Y1, Incorrect_Range);
+            return _mm256_permute2f128_pd(x, y, (L < Y0 ? L : L - Y0 + 2) + (H < Y0 ? H : H - Y0 + 2) * (1 << 4));
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3> static inline __m256d ALWAYS_INLINE CONST permute(__m256d x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= X2 && Dst3 >= X2, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X1 && Dst1 <= X1 && Dst2 <= X3 && Dst3 <= X3, Incorrect_Range);
+            return _mm256_permute_pd(x, Dst0 + Dst1 * 2 + (Dst2 - X2) * 4 + (Dst3 - X2) * 8);
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3> static inline __m256 ALWAYS_INLINE CONST permute(__m256 x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= X0 && Dst3 >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X3 && Dst1 <= X3 && Dst2 <= X3 && Dst3 <= X3, Incorrect_Range);
+            return _mm256_permute_ps(x, Dst0 + Dst1 * 4 + Dst2 * 16 + Dst3 * 64);
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3> static inline __m256i ALWAYS_INLINE CONST permute(__m256i x) {
+            return _mm256_castps_si256(permute<Dst0, Dst1, Dst2, Dst3>(_mm256_castsi256_ps(x)));
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3> static inline __m256d ALWAYS_INLINE CONST shuffle(__m256d x, __m256d y) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= Y0 && Dst2 >= X2 && Dst3 >= Y2, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X1 && Dst1 <= Y1 && Dst2 <= X3 && Dst3 <= Y3, Incorrect_Range);
+            return _mm256_shuffle_pd(x, y, Dst0 + (Dst1 - Y0) * 2 + (Dst2 - X2) * 4 + (Dst3 - Y2) * 8);
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3> static inline __m256 ALWAYS_INLINE CONST shuffle(__m256 x, __m256 y) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= Y0 && Dst3 >= Y0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X3 && Dst1 <= X3 && Dst2 <= Y3 && Dst3 <= Y3, Incorrect_Range);
+            return _mm256_shuffle_ps(x, y, Dst0 + Dst1 * 4 + (Dst2 - Y0) * 16 + (Dst3 - Y0) * 64);
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3, VecPos Dst4, VecPos Dst5, VecPos Dst6, VecPos Dst7>
+        static inline __m256 ALWAYS_INLINE CONST blend(__m256 x, __m256 y) {
+            VC_STATIC_ASSERT(Dst0 == X0 || Dst0 == Y0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst1 == X1 || Dst1 == Y1, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst2 == X2 || Dst2 == Y2, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst3 == X3 || Dst3 == Y3, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst4 == X4 || Dst4 == Y4, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst5 == X5 || Dst5 == Y5, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst6 == X6 || Dst6 == Y6, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst7 == X7 || Dst7 == Y7, Incorrect_Range);
+            return _mm256_blend_ps(x, y,
+                    (Dst0 / Y0) *  1 + (Dst1 / Y1) *  2 +
+                    (Dst2 / Y2) *  4 + (Dst3 / Y3) *  8 +
+                    (Dst4 / Y4) * 16 + (Dst5 / Y5) * 32 +
+                    (Dst6 / Y6) * 64 + (Dst7 / Y7) *128
+                    );
+        }
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3, VecPos Dst4, VecPos Dst5, VecPos Dst6, VecPos Dst7>
+        static inline __m256i ALWAYS_INLINE CONST blend(__m256i x, __m256i y) {
+            return _mm256_castps_si256(blend<Dst0, Dst1, Dst2, Dst3, Dst4, Dst5, Dst6, Dst7>(_mm256_castsi256_ps(x), _mm256_castsi256_ps(y)));
+        }
+        template<VecPos Dst> struct ScaleForBlend { enum { Value = Dst >= X4 ? Dst - X4 + Y0 : Dst }; };
+        template<VecPos Dst0, VecPos Dst1, VecPos Dst2, VecPos Dst3, VecPos Dst4, VecPos Dst5, VecPos Dst6, VecPos Dst7>
+        static inline __m256 ALWAYS_INLINE CONST permute(__m256 x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst0 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst1 >= X0 && Dst1 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst2 >= X0 && Dst2 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst3 >= X0 && Dst3 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst4 >= X0 && Dst4 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst5 >= X0 && Dst5 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst6 >= X0 && Dst6 <= X7, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst7 >= X0 && Dst7 <= X7, Incorrect_Range);
+            if (Dst0 + X4 == Dst4 && Dst1 + X4 == Dst5 && Dst2 + X4 == Dst6 && Dst3 + X4 == Dst7) {
+                return permute<Dst0, Dst1, Dst2, Dst3>(x);
+            }
+            const __m128 loIn = _mm256_castps256_ps128(x);
+            const __m128 hiIn = _mm256_extractf128_ps(x, 1);
+            __m128 lo, hi;
+
+            if (Dst0 < X4 && Dst1 < X4 && Dst2 < X4 && Dst3 < X4) {
+                lo = _mm_permute_ps(loIn, Dst0 + Dst1 * 4 + Dst2 * 16 + Dst3 * 64);
+            } else if (Dst0 >= X4 && Dst1 >= X4 && Dst2 >= X4 && Dst3 >= X4) {
+                lo = _mm_permute_ps(hiIn, Dst0 + Dst1 * 4 + Dst2 * 16 + Dst3 * 64);
+            } else if (Dst0 < X4 && Dst1 < X4 && Dst2 >= X4 && Dst3 >= X4) {
+                lo = shuffle<Dst0, Dst1, Dst2 - X4 + Y0, Dst3 - X4 + Y0>(loIn, hiIn);
+            } else if (Dst0 >= X4 && Dst1 >= X4 && Dst2 < X4 && Dst3 < X4) {
+                lo = shuffle<Dst0 - X4, Dst1 - X4, Dst2 + Y0, Dst3 + Y0>(hiIn, loIn);
+            } else if (Dst0 == X0 && Dst1 == X4 && Dst2 == X1 && Dst3 == X5) {
+                lo = _mm_unpacklo_ps(loIn, hiIn);
+            } else if (Dst0 == X4 && Dst1 == X0 && Dst2 == X5 && Dst3 == X1) {
+                lo = _mm_unpacklo_ps(hiIn, loIn);
+            } else if (Dst0 == X2 && Dst1 == X6 && Dst2 == X3 && Dst3 == X7) {
+                lo = _mm_unpackhi_ps(loIn, hiIn);
+            } else if (Dst0 == X6 && Dst1 == X2 && Dst2 == X7 && Dst3 == X3) {
+                lo = _mm_unpackhi_ps(hiIn, loIn);
+            } else if (Dst0 % X4 == 0 && Dst1 % X4 == 1 && Dst2 % X4 == 2 && Dst3 % X4 == 3) {
+                lo = blend<ScaleForBlend<Dst0>::Value, ScaleForBlend<Dst1>::Value,
+                   ScaleForBlend<Dst2>::Value, ScaleForBlend<Dst3>::Value>(loIn, hiIn);
+            }
+
+            if (Dst4 >= X4 && Dst5 >= X4 && Dst6 >= X4 && Dst7 >= X4) {
+                hi = _mm_permute_ps(hiIn, (Dst4 - X4) + (Dst5 - X4) * 4 + (Dst6 - X4) * 16 + (Dst7 - X4) * 64);
+            } else if (Dst4 < X4 && Dst5 < X4 && Dst6 < X4 && Dst7 < X4) {
+                hi = _mm_permute_ps(loIn, (Dst4 - X4) + (Dst5 - X4) * 4 + (Dst6 - X4) * 16 + (Dst7 - X4) * 64);
+            } else if (Dst4 < X4 && Dst5 < X4 && Dst6 >= X4 && Dst7 >= X4) {
+                hi = shuffle<Dst4, Dst5, Dst6 - X4 + Y0, Dst7 - X4 + Y0>(loIn, hiIn);
+            } else if (Dst4 >= X4 && Dst5 >= X4 && Dst6 < X4 && Dst7 < X4) {
+                hi = shuffle<Dst4 - X4, Dst5 - X4, Dst6 + Y0, Dst7 + Y0>(hiIn, loIn);
+            } else if (Dst4 == X0 && Dst5 == X4 && Dst6 == X1 && Dst7 == X5) {
+                hi = _mm_unpacklo_ps(loIn, hiIn);
+            } else if (Dst4 == X4 && Dst5 == X0 && Dst6 == X5 && Dst7 == X1) {
+                hi = _mm_unpacklo_ps(hiIn, loIn);
+            } else if (Dst4 == X2 && Dst5 == X6 && Dst6 == X3 && Dst7 == X7) {
+                hi = _mm_unpackhi_ps(loIn, hiIn);
+            } else if (Dst4 == X6 && Dst5 == X2 && Dst6 == X7 && Dst7 == X3) {
+                hi = _mm_unpackhi_ps(hiIn, loIn);
+            } else if (Dst4 % X4 == 0 && Dst5 % X4 == 1 && Dst6 % X4 == 2 && Dst7 % X4 == 3) {
+                hi = blend<ScaleForBlend<Dst4>::Value, ScaleForBlend<Dst5>::Value,
+                   ScaleForBlend<Dst6>::Value, ScaleForBlend<Dst7>::Value>(loIn, hiIn);
+            }
+
+            return _mm256_insertf128_ps(_mm256_castps128_ps256(lo), hi, 1);
+        }
+    } // namespace Mem
+
+    // little endian has the lo bits on the right and high bits on the left
+    // with vectors this becomes greatly confusing:
+    // Mem: abcd
+    // Reg: dcba
+    //
+    // The shuffles and permutes above use memory ordering. The ones below use register ordering:
+    namespace Reg
+    {
+        template<VecPos H, VecPos L> static inline __m256 ALWAYS_INLINE CONST permute128(__m256 x, __m256 y) {
+            VC_STATIC_ASSERT(L >= X0 && H >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(L <= Y1 && H <= Y1, Incorrect_Range);
+            return _mm256_permute2f128_ps(x, y, (L < Y0 ? L : L - Y0 + 2) + (H < Y0 ? H : H - Y0 + 2) * (1 << 4));
+        }
+        template<VecPos H, VecPos L> static inline __m256i ALWAYS_INLINE CONST permute128(__m256i x, __m256i y) {
+            VC_STATIC_ASSERT(L >= X0 && H >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(L <= Y1 && H <= Y1, Incorrect_Range);
+            return _mm256_permute2f128_si256(x, y, (L < Y0 ? L : L - Y0 + 2) + (H < Y0 ? H : H - Y0 + 2) * (1 << 4));
+        }
+        template<VecPos H, VecPos L> static inline __m256d ALWAYS_INLINE CONST permute128(__m256d x, __m256d y) {
+            VC_STATIC_ASSERT(L >= X0 && H >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(L <= Y1 && H <= Y1, Incorrect_Range);
+            return _mm256_permute2f128_pd(x, y, (L < Y0 ? L : L - Y0 + 2) + (H < Y0 ? H : H - Y0 + 2) * (1 << 4));
+        }
+        template<VecPos Dst3, VecPos Dst2, VecPos Dst1, VecPos Dst0> static inline __m256d ALWAYS_INLINE CONST permute(__m256d x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= X2 && Dst3 >= X2, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X1 && Dst1 <= X1 && Dst2 <= X3 && Dst3 <= X3, Incorrect_Range);
+            return _mm256_permute_pd(x, Dst0 + Dst1 * 2 + (Dst2 - X2) * 4 + (Dst3 - X2) * 8);
+        }
+        template<VecPos Dst3, VecPos Dst2, VecPos Dst1, VecPos Dst0> static inline __m256 ALWAYS_INLINE CONST permute(__m256 x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= X0 && Dst3 >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X3 && Dst1 <= X3 && Dst2 <= X3 && Dst3 <= X3, Incorrect_Range);
+            return _mm256_permute_ps(x, Dst0 + Dst1 * 4 + Dst2 * 16 + Dst3 * 64);
+        }
+        template<VecPos Dst1, VecPos Dst0> static inline __m128d ALWAYS_INLINE CONST permute(__m128d x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X1 && Dst1 <= X1, Incorrect_Range);
+            return _mm_permute_pd(x, Dst0 + Dst1 * 2);
+        }
+        template<VecPos Dst3, VecPos Dst2, VecPos Dst1, VecPos Dst0> static inline __m128 ALWAYS_INLINE CONST permute(__m128 x) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= X0 && Dst3 >= X0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X3 && Dst1 <= X3 && Dst2 <= X3 && Dst3 <= X3, Incorrect_Range);
+            return _mm_permute_ps(x, Dst0 + Dst1 * 4 + Dst2 * 16 + Dst3 * 64);
+        }
+        template<VecPos Dst3, VecPos Dst2, VecPos Dst1, VecPos Dst0> static inline __m256d ALWAYS_INLINE CONST shuffle(__m256d x, __m256d y) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= Y0 && Dst2 >= X2 && Dst3 >= Y2, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X1 && Dst1 <= Y1 && Dst2 <= X3 && Dst3 <= Y3, Incorrect_Range);
+            return _mm256_shuffle_pd(x, y, Dst0 + (Dst1 - Y0) * 2 + (Dst2 - X2) * 4 + (Dst3 - Y2) * 8);
+        }
+        template<VecPos Dst3, VecPos Dst2, VecPos Dst1, VecPos Dst0> static inline __m256 ALWAYS_INLINE CONST shuffle(__m256 x, __m256 y) {
+            VC_STATIC_ASSERT(Dst0 >= X0 && Dst1 >= X0 && Dst2 >= Y0 && Dst3 >= Y0, Incorrect_Range);
+            VC_STATIC_ASSERT(Dst0 <= X3 && Dst1 <= X3 && Dst2 <= Y3 && Dst3 <= Y3, Incorrect_Range);
+            return _mm256_shuffle_ps(x, y, Dst0 + Dst1 * 4 + (Dst2 - Y0) * 16 + (Dst3 - Y0) * 64);
+        }
+    } // namespace Reg
+} // namespace Vc
+
+#endif // VC_AVX_SHUFFLE_H
diff --git a/Vc/include/Vc/avx/sorthelper.h b/Vc/include/Vc/avx/sorthelper.h
new file mode 100644 (file)
index 0000000..9544f1f
--- /dev/null
@@ -0,0 +1,38 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_SORTHELPER_H
+#define VC_AVX_SORTHELPER_H
+
+#include "types.h"
+
+namespace Vc
+{
+namespace AVX
+{
+template<typename T> struct SortHelper
+{
+    typedef typename VectorTypeHelper<T>::Type VectorType;
+    static VectorType sort(VectorType);
+    static void sort(VectorType &, VectorType &);
+};
+} // namespace AVX
+} // namespace Vc
+
+#endif // VC_AVX_SORTHELPER_H
diff --git a/Vc/include/Vc/avx/types.h b/Vc/include/Vc/avx/types.h
new file mode 100644 (file)
index 0000000..cca7290
--- /dev/null
@@ -0,0 +1,100 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AVX_TYPES_H
+#define AVX_TYPES_H
+
+#include "intrinsics.h"
+#include "../common/storage.h"
+#include "macros.h"
+
+#define VC_DOUBLE_V_SIZE 4
+#define VC_FLOAT_V_SIZE 8
+#define VC_SFLOAT_V_SIZE 8
+#define VC_INT_V_SIZE 8
+#define VC_UINT_V_SIZE 8
+#define VC_SHORT_V_SIZE 8
+#define VC_USHORT_V_SIZE 8
+
+#include "../common/types.h"
+
+namespace Vc
+{
+namespace AVX
+{
+    template<typename T> class Vector;
+
+    template<unsigned int VectorSize, size_t RegisterWidth> class Mask;
+
+    template<typename T> struct VectorHelper {};
+    template<typename T> struct GatherHelper;
+    template<typename T> struct ScatterHelper;
+
+    template<typename T> struct IndexTypeHelper;
+    template<> struct IndexTypeHelper<         char > { typedef unsigned char  Type; };
+    template<> struct IndexTypeHelper<unsigned char > { typedef unsigned char  Type; };
+    template<> struct IndexTypeHelper<         short> { typedef unsigned short Type; };
+    template<> struct IndexTypeHelper<unsigned short> { typedef unsigned short Type; };
+    template<> struct IndexTypeHelper<         int  > { typedef unsigned int   Type; };
+    template<> struct IndexTypeHelper<unsigned int  > { typedef unsigned int   Type; };
+    template<> struct IndexTypeHelper<         float> { typedef unsigned int   Type; };
+    template<> struct IndexTypeHelper<        sfloat> { typedef unsigned short Type; };
+    template<> struct IndexTypeHelper<        double> { typedef unsigned int   Type; }; // _M128I based int32 would be nice
+
+    template<typename T> struct VectorTypeHelper;
+    template<> struct VectorTypeHelper<         char > { typedef __m128i Type; };
+    template<> struct VectorTypeHelper<unsigned char > { typedef __m128i Type; };
+    template<> struct VectorTypeHelper<         short> { typedef __m128i Type; };
+    template<> struct VectorTypeHelper<unsigned short> { typedef __m128i Type; };
+    template<> struct VectorTypeHelper<         int  > { typedef _M256I Type; };
+    template<> struct VectorTypeHelper<unsigned int  > { typedef _M256I Type; };
+    template<> struct VectorTypeHelper<         float> { typedef _M256  Type; };
+    template<> struct VectorTypeHelper<        sfloat> { typedef _M256  Type; };
+    template<> struct VectorTypeHelper<        double> { typedef _M256D Type; };
+
+    template<typename T> struct HasVectorDivisionHelper { enum { Value = 1 }; };
+    //template<> struct HasVectorDivisionHelper<unsigned int> { enum { Value = 0 }; };
+
+    template<typename T> struct VectorHelperSize;
+
+#ifdef VC_MSVC
+    // MSVC's __declspec(align(#)) only works with numbers, no enums or sizeof allowed ;(
+    template<size_t size> class _VectorAlignedBaseHack;
+    template<> class STRUCT_ALIGN1( 8) _VectorAlignedBaseHack< 8> {} STRUCT_ALIGN2( 8);
+    template<> class STRUCT_ALIGN1(16) _VectorAlignedBaseHack<16> {} STRUCT_ALIGN2(16);
+    template<> class STRUCT_ALIGN1(32) _VectorAlignedBaseHack<32> {} STRUCT_ALIGN2(32);
+    template<> class STRUCT_ALIGN1(64) _VectorAlignedBaseHack<64> {} STRUCT_ALIGN2(64);
+    template<typename V = Vector<float> >
+    class VectorAlignedBaseT : public _VectorAlignedBaseHack<sizeof(V)>
+    {
+        public:
+            FREE_STORE_OPERATORS_ALIGNED(sizeof(V))
+    };
+#else
+    template<typename V = Vector<float> >
+    class STRUCT_ALIGN1(sizeof(V)) VectorAlignedBaseT
+    {
+        public:
+            FREE_STORE_OPERATORS_ALIGNED(sizeof(V))
+    } STRUCT_ALIGN2(sizeof(V));
+#endif
+} // namespace AVX
+} // namespace Vc
+
+#endif // AVX_TYPES_H
diff --git a/Vc/include/Vc/avx/undomacros.h b/Vc/include/Vc/avx/undomacros.h
new file mode 100644 (file)
index 0000000..637116d
--- /dev/null
@@ -0,0 +1,26 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_UNDOMACROS_H
+#define VC_AVX_UNDOMACROS_H
+#undef VC_AVX_MACROS_H
+
+#endif // VC_AVX_UNDOMACROS_H
+
+#include "../common/undomacros.h"
diff --git a/Vc/include/Vc/avx/vector.h b/Vc/include/Vc/avx/vector.h
new file mode 100644 (file)
index 0000000..a32b20e
--- /dev/null
@@ -0,0 +1,449 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AVX_VECTOR_H
+#define AVX_VECTOR_H
+
+#include "intrinsics.h"
+#include "vectorhelper.h"
+#include "mask.h"
+#include "writemaskedvector.h"
+#include "sorthelper.h"
+#include <algorithm>
+#include <cmath>
+#include "../common/aliasingentryhelper.h"
+#include "../common/memoryfwd.h"
+#include "macros.h"
+
+#ifdef isfinite
+#undef isfinite
+#endif
+#ifdef isnan
+#undef isnan
+#endif
+
+namespace Vc
+{
+namespace AVX
+{
+enum VectorAlignmentEnum { VectorAlignment = 32 };
+
+template<typename T> class Vector
+{
+    public:
+        FREE_STORE_OPERATORS_ALIGNED(32)
+
+        typedef typename VectorTypeHelper<T>::Type VectorType;
+        typedef typename DetermineEntryType<T>::Type EntryType;
+        enum Constants {
+            Size = sizeof(VectorType) / sizeof(EntryType),
+            HasVectorDivision = HasVectorDivisionHelper<T>::Value
+        };
+        typedef Vector<typename IndexTypeHelper<T>::Type> IndexType;
+        typedef typename Vc::AVX::Mask<Size, sizeof(VectorType)> Mask;
+        typedef typename Mask::AsArg MaskArg;
+        typedef Vc::Memory<Vector<T>, Size> Memory;
+#ifdef VC_PASSING_VECTOR_BY_VALUE_IS_BROKEN
+        typedef const Vector<T> &AsArg;
+#else
+        typedef Vector<T> AsArg;
+#endif
+
+    protected:
+        // helper that specializes on VectorType
+        typedef VectorHelper<VectorType> HV;
+
+        // helper that specializes on T
+        typedef VectorHelper<T> HT;
+
+        // cast any m256/m128 to VectorType
+        static inline VectorType INTRINSIC _cast(__m128  v) { return avx_cast<VectorType>(v); }
+        static inline VectorType INTRINSIC _cast(__m128i v) { return avx_cast<VectorType>(v); }
+        static inline VectorType INTRINSIC _cast(__m128d v) { return avx_cast<VectorType>(v); }
+        static inline VectorType INTRINSIC _cast(__m256  v) { return avx_cast<VectorType>(v); }
+        static inline VectorType INTRINSIC _cast(__m256i v) { return avx_cast<VectorType>(v); }
+        static inline VectorType INTRINSIC _cast(__m256d v) { return avx_cast<VectorType>(v); }
+
+        typedef Common::VectorMemoryUnion<VectorType, EntryType> StorageType;
+        StorageType d;
+
+    public:
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // uninitialized
+        inline Vector() {}
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // constants
+        explicit Vector(VectorSpecialInitializerZero::ZEnum);
+        explicit Vector(VectorSpecialInitializerOne::OEnum);
+        explicit Vector(VectorSpecialInitializerIndexesFromZero::IEnum);
+        static Vector Zero();
+        static Vector One();
+        static Vector IndexesFromZero();
+        static Vector Random();
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // internal: required to enable returning objects of VectorType
+        inline Vector(const VectorType &x) : d(x) {}
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // static_cast / copy ctor
+        template<typename T2> explicit Vector(Vector<T2> x);
+
+        // implicit cast
+        template<typename OtherT> inline INTRINSIC_L Vector &operator=(const Vector<OtherT> &x) INTRINSIC_R;
+
+        // copy assignment
+        inline Vector &operator=(AsArg v) { d.v() = v.d.v(); return *this; }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // broadcast
+        explicit Vector(EntryType a);
+        template<typename TT> inline INTRINSIC Vector(TT x, VC_EXACT_TYPE(TT, EntryType, void *) = 0) : d(HT::set(x)) {}
+        inline Vector &operator=(EntryType a) { d.v() = HT::set(a); return *this; }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // load ctors
+        explicit inline INTRINSIC_L
+            Vector(const EntryType *x) INTRINSIC_R;
+        template<typename Alignment> inline INTRINSIC_L
+            Vector(const EntryType *x, Alignment align) INTRINSIC_R;
+        template<typename OtherT> explicit inline INTRINSIC_L
+            Vector(const OtherT    *x) INTRINSIC_R;
+        template<typename OtherT, typename Alignment> inline INTRINSIC_L
+            Vector(const OtherT    *x, Alignment align) INTRINSIC_R;
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // load member functions
+        inline INTRINSIC_L
+            void load(const EntryType *mem) INTRINSIC_R;
+        template<typename Alignment> inline INTRINSIC_L
+            void load(const EntryType *mem, Alignment align) INTRINSIC_R;
+        template<typename OtherT> inline INTRINSIC_L
+            void load(const OtherT    *mem) INTRINSIC_R;
+        template<typename OtherT, typename Alignment> inline INTRINSIC_L
+            void load(const OtherT    *mem, Alignment align) INTRINSIC_R;
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // expand/merge 1 float_v <=> 2 double_v          XXX rationale? remove it for release? XXX
+        explicit inline Vector(const Vector<typename HT::ConcatType> *a);
+        inline void expand(Vector<typename HT::ConcatType> *x) const;
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // zeroing
+        inline void setZero();
+        inline void setZero(const Mask &k);
+
+        void setQnan();
+        void setQnan(MaskArg k);
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // stores
+        inline void store(EntryType *mem) const;
+        inline void store(EntryType *mem, const Mask &mask) const;
+        template<typename A> inline void store(EntryType *mem, A align) const;
+        template<typename A> inline void store(EntryType *mem, const Mask &mask, A align) const;
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // swizzles
+        inline const Vector<T> INTRINSIC_L CONST_L &abcd() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  cdab() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  badc() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  aaaa() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  bbbb() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  cccc() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  dddd() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  bcad() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  bcda() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  dabc() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  acbd() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  dbca() const INTRINSIC_R CONST_R;
+        inline const Vector<T> INTRINSIC_L CONST_L  dcba() const INTRINSIC_R CONST_R;
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // gathers
+        template<typename IndexT> Vector(const EntryType *mem, const IndexT *indexes);
+        template<typename IndexT> Vector(const EntryType *mem, Vector<IndexT> indexes);
+        template<typename IndexT> Vector(const EntryType *mem, const IndexT *indexes, MaskArg mask);
+        template<typename IndexT> Vector(const EntryType *mem, Vector<IndexT> indexes, MaskArg mask);
+        template<typename S1, typename IT> Vector(const S1 *array, const EntryType S1::* member1, IT indexes);
+        template<typename S1, typename IT> Vector(const S1 *array, const EntryType S1::* member1, IT indexes, MaskArg mask);
+        template<typename S1, typename S2, typename IT> Vector(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes);
+        template<typename S1, typename S2, typename IT> Vector(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes, MaskArg mask);
+        template<typename S1, typename IT1, typename IT2> Vector(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes);
+        template<typename S1, typename IT1, typename IT2> Vector(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes, MaskArg mask);
+        template<typename Index> void gather(const EntryType *mem, Index indexes);
+        template<typename Index> void gather(const EntryType *mem, Index indexes, MaskArg mask);
+#ifdef VC_USE_SET_GATHERS
+        template<typename IT> void gather(const EntryType *mem, Vector<IT> indexes, MaskArg mask);
+#endif
+        template<typename S1, typename IT> void gather(const S1 *array, const EntryType S1::* member1, IT indexes);
+        template<typename S1, typename IT> void gather(const S1 *array, const EntryType S1::* member1, IT indexes, MaskArg mask);
+        template<typename S1, typename S2, typename IT> void gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes);
+        template<typename S1, typename S2, typename IT> void gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes, MaskArg mask);
+        template<typename S1, typename IT1, typename IT2> void gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes);
+        template<typename S1, typename IT1, typename IT2> void gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes, MaskArg mask);
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // scatters
+        template<typename Index> void scatter(EntryType *mem, Index indexes) const;
+        template<typename Index> void scatter(EntryType *mem, Index indexes, MaskArg mask) const;
+        template<typename S1, typename IT> void scatter(S1 *array, EntryType S1::* member1, IT indexes) const;
+        template<typename S1, typename IT> void scatter(S1 *array, EntryType S1::* member1, IT indexes, MaskArg mask) const;
+        template<typename S1, typename S2, typename IT> void scatter(S1 *array, S2 S1::* member1, EntryType S2::* member2, IT indexes) const;
+        template<typename S1, typename S2, typename IT> void scatter(S1 *array, S2 S1::* member1, EntryType S2::* member2, IT indexes, MaskArg mask) const;
+        template<typename S1, typename IT1, typename IT2> void scatter(S1 *array, EntryType *S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes) const;
+        template<typename S1, typename IT1, typename IT2> void scatter(S1 *array, EntryType *S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes, MaskArg mask) const;
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        //prefix
+        inline Vector ALWAYS_INLINE &operator++() { data() = VectorHelper<T>::add(data(), VectorHelper<T>::one()); return *this; }
+        //postfix
+        inline Vector ALWAYS_INLINE operator++(int) { const Vector<T> r = *this; data() = VectorHelper<T>::add(data(), VectorHelper<T>::one()); return r; }
+
+        inline Common::AliasingEntryHelper<StorageType> INTRINSIC operator[](int index) {
+#if defined(VC_GCC) && VC_GCC >= 0x40300 && VC_GCC < 0x40400
+            ::Vc::Warnings::_operator_bracket_warning();
+#endif
+            return d.m(index);
+        }
+        inline EntryType ALWAYS_INLINE operator[](int index) const {
+            return d.m(index);
+        }
+
+        inline Vector ALWAYS_INLINE operator~() const { return VectorHelper<VectorType>::andnot_(data(), VectorHelper<VectorType>::allone()); }
+        inline Vector<typename NegateTypeHelper<T>::Type> operator-() const;
+
+#define OP1(fun) \
+        inline Vector fun() const { return Vector<T>(VectorHelper<T>::fun(data())); } \
+        inline Vector &fun##_eq() { data() = VectorHelper<T>::fun(data()); return *this; }
+        OP1(sqrt)
+        OP1(abs)
+#undef OP1
+
+#define OP(symbol, fun) \
+        inline Vector ALWAYS_INLINE &operator symbol##=(const Vector<T> &x) { data() = VectorHelper<T>::fun(data(), x.data()); return *this; } \
+        inline Vector ALWAYS_INLINE &operator symbol##=(EntryType x) { return operator symbol##=(Vector(x)); } \
+        inline Vector ALWAYS_INLINE operator symbol(const Vector<T> &x) const { return Vector<T>(VectorHelper<T>::fun(data(), x.data())); } \
+        template<typename TT> inline VC_EXACT_TYPE(TT, EntryType, Vector) ALWAYS_INLINE operator symbol(TT x) const { return operator symbol(Vector(x)); }
+
+        OP(+, add)
+        OP(-, sub)
+        OP(*, mul)
+#undef OP
+        inline Vector &operator/=(EntryType x);
+        template<typename TT> inline PURE_L VC_EXACT_TYPE(TT, EntryType, Vector) operator/(TT x) const PURE_R;
+        inline Vector &operator/=(const Vector<T> &x);
+        inline Vector  operator/ (const Vector<T> &x) const;
+
+        // bitwise ops
+#define OP_VEC(op) \
+        inline Vector<T> ALWAYS_INLINE_L &operator op##=(AsArg x) ALWAYS_INLINE_R; \
+        inline Vector<T> ALWAYS_INLINE_L  operator op   (AsArg x) const ALWAYS_INLINE_R;
+#define OP_ENTRY(op) \
+        inline ALWAYS_INLINE Vector<T> &operator op##=(EntryType x) { return operator op##=(Vector(x)); } \
+        template<typename TT> inline ALWAYS_INLINE VC_EXACT_TYPE(TT, EntryType, Vector) operator op(TT x) const { return operator op(Vector(x)); }
+        VC_ALL_BINARY(OP_VEC)
+        VC_ALL_BINARY(OP_ENTRY)
+        VC_ALL_SHIFTS(OP_VEC)
+#undef OP_VEC
+#undef OP_ENTRY
+
+        inline Vector<T> ALWAYS_INLINE_L &operator>>=(int x) ALWAYS_INLINE_R;
+        inline Vector<T> ALWAYS_INLINE_L &operator<<=(int x) ALWAYS_INLINE_R;
+        inline Vector<T> ALWAYS_INLINE_L operator>>(int x) const ALWAYS_INLINE_R;
+        inline Vector<T> ALWAYS_INLINE_L operator<<(int x) const ALWAYS_INLINE_R;
+
+#define OPcmp(symbol, fun) \
+        inline Mask ALWAYS_INLINE operator symbol(AsArg x) const { return VectorHelper<T>::fun(data(), x.data()); } \
+        template<typename TT> inline VC_EXACT_TYPE(TT, EntryType, Mask) ALWAYS_INLINE operator symbol(TT x) const { return operator symbol(Vector(x)); }
+
+        OPcmp(==, cmpeq)
+        OPcmp(!=, cmpneq)
+        OPcmp(>=, cmpnlt)
+        OPcmp(>, cmpnle)
+        OPcmp(<, cmplt)
+        OPcmp(<=, cmple)
+#undef OPcmp
+
+        inline void multiplyAndAdd(const Vector<T> &factor, const Vector<T> &summand) {
+            VectorHelper<T>::multiplyAndAdd(data(), factor, summand);
+        }
+
+        inline void assign( const Vector<T> &v, const Mask &mask ) {
+            const VectorType k = avx_cast<VectorType>(mask.data());
+            data() = VectorHelper<VectorType>::blend(data(), v.data(), k);
+        }
+
+        template<typename V2> inline V2 staticCast() const { return V2(*this); }
+        template<typename V2> inline V2 reinterpretCast() const { return avx_cast<typename V2::VectorType>(data()); }
+
+        inline WriteMaskedVector<T> ALWAYS_INLINE operator()(const Mask &k) { return WriteMaskedVector<T>(this, k); }
+
+        /**
+         * \return \p true  This vector was completely filled. m2 might be 0 or != 0. You still have
+         *                  to test this.
+         *         \p false This vector was not completely filled. m2 is all 0.
+         */
+        //inline bool pack(Mask &m1, Vector<T> &v2, Mask &m2) {
+            //return VectorHelper<T>::pack(data(), m1.data, v2.data(), m2.data);
+        //}
+
+        inline VectorType &data() { return d.v(); }
+        inline const VectorType &data() const { return d.v(); }
+
+        inline EntryType min() const { return VectorHelper<T>::min(data()); }
+        inline EntryType max() const { return VectorHelper<T>::max(data()); }
+        inline EntryType product() const { return VectorHelper<T>::mul(data()); }
+        inline EntryType sum() const { return VectorHelper<T>::add(data()); }
+        inline EntryType min(MaskArg m) const;
+        inline EntryType max(MaskArg m) const;
+        inline EntryType product(MaskArg m) const;
+        inline EntryType sum(MaskArg m) const;
+
+        inline Vector sorted() const { return SortHelper<T>::sort(data()); }
+
+        template<typename F> void callWithValuesSorted(F &f) {
+            EntryType value = d.m(0);
+            f(value);
+            for (int i = 1; i < Size; ++i) {
+                if (d.m(i) != value) {
+                    value = d.m(i);
+                    f(value);
+                }
+            }
+        }
+
+        template<typename F> inline void INTRINSIC call(const F &f) const {
+            for_all_vector_entries(i,
+                    f(EntryType(d.m(i)));
+                    );
+        }
+        template<typename F> inline void INTRINSIC call(F &f) const {
+            for_all_vector_entries(i,
+                    f(EntryType(d.m(i)));
+                    );
+        }
+
+        template<typename F> inline void INTRINSIC call(const F &f, const Mask &mask) const {
+            Vc_foreach_bit(size_t i, mask) {
+                f(EntryType(d.m(i)));
+            }
+        }
+        template<typename F> inline void INTRINSIC call(F &f, const Mask &mask) const {
+            Vc_foreach_bit(size_t i, mask) {
+                f(EntryType(d.m(i)));
+            }
+        }
+
+        template<typename F> inline Vector<T> INTRINSIC apply(const F &f) const {
+            Vector<T> r;
+            for_all_vector_entries(i,
+                    r.d.m(i) = f(EntryType(d.m(i)));
+                    );
+            return r;
+        }
+        template<typename F> inline Vector<T> INTRINSIC apply(F &f) const {
+            Vector<T> r;
+            for_all_vector_entries(i,
+                    r.d.m(i) = f(EntryType(d.m(i)));
+                    );
+            return r;
+        }
+
+        template<typename F> inline Vector<T> INTRINSIC apply(const F &f, const Mask &mask) const {
+            Vector<T> r(*this);
+            Vc_foreach_bit (size_t i, mask) {
+                r.d.m(i) = f(EntryType(r.d.m(i)));
+            }
+            return r;
+        }
+        template<typename F> inline Vector<T> INTRINSIC apply(F &f, const Mask &mask) const {
+            Vector<T> r(*this);
+            Vc_foreach_bit (size_t i, mask) {
+                r.d.m(i) = f(EntryType(r.d.m(i)));
+            }
+            return r;
+        }
+
+        template<typename IndexT> inline void INTRINSIC fill(EntryType (&f)(IndexT)) {
+            for_all_vector_entries(i,
+                    d.m(i) = f(i);
+                    );
+        }
+        inline void INTRINSIC fill(EntryType (&f)()) {
+            for_all_vector_entries(i,
+                    d.m(i) = f();
+                    );
+        }
+
+        inline INTRINSIC_L Vector copySign(AsArg reference) const INTRINSIC_R;
+        inline INTRINSIC_L Vector exponent() const INTRINSIC_R;
+};
+
+typedef Vector<double>         double_v;
+typedef Vector<float>          float_v;
+typedef Vector<sfloat>         sfloat_v;
+typedef Vector<int>            int_v;
+typedef Vector<unsigned int>   uint_v;
+typedef Vector<short>          short_v;
+typedef Vector<unsigned short> ushort_v;
+typedef double_v::Mask double_m;
+typedef  float_v::Mask float_m;
+typedef sfloat_v::Mask sfloat_m;
+typedef    int_v::Mask int_m;
+typedef   uint_v::Mask uint_m;
+typedef  short_v::Mask short_m;
+typedef ushort_v::Mask ushort_m;
+
+template<typename T> class SwizzledVector : public Vector<T> {};
+
+static inline int_v    min(const int_v    &x, const int_v    &y) { return _mm256_min_epi32(x.data(), y.data()); }
+static inline uint_v   min(const uint_v   &x, const uint_v   &y) { return _mm256_min_epu32(x.data(), y.data()); }
+static inline short_v  min(const short_v  &x, const short_v  &y) { return _mm_min_epi16(x.data(), y.data()); }
+static inline ushort_v min(const ushort_v &x, const ushort_v &y) { return _mm_min_epu16(x.data(), y.data()); }
+static inline float_v  min(const float_v  &x, const float_v  &y) { return _mm256_min_ps(x.data(), y.data()); }
+static inline sfloat_v min(const sfloat_v &x, const sfloat_v &y) { return _mm256_min_ps(x.data(), y.data()); }
+static inline double_v min(const double_v &x, const double_v &y) { return _mm256_min_pd(x.data(), y.data()); }
+static inline int_v    max(const int_v    &x, const int_v    &y) { return _mm256_max_epi32(x.data(), y.data()); }
+static inline uint_v   max(const uint_v   &x, const uint_v   &y) { return _mm256_max_epu32(x.data(), y.data()); }
+static inline short_v  max(const short_v  &x, const short_v  &y) { return _mm_max_epi16(x.data(), y.data()); }
+static inline ushort_v max(const ushort_v &x, const ushort_v &y) { return _mm_max_epu16(x.data(), y.data()); }
+static inline float_v  max(const float_v  &x, const float_v  &y) { return _mm256_max_ps(x.data(), y.data()); }
+static inline sfloat_v max(const sfloat_v &x, const sfloat_v &y) { return _mm256_max_ps(x.data(), y.data()); }
+static inline double_v max(const double_v &x, const double_v &y) { return _mm256_max_pd(x.data(), y.data()); }
+
+  template<typename T> static inline Vector<T> sqrt (const Vector<T> &x) { return VectorHelper<T>::sqrt(x.data()); }
+  template<typename T> static inline Vector<T> rsqrt(const Vector<T> &x) { return VectorHelper<T>::rsqrt(x.data()); }
+  template<typename T> static inline Vector<T> abs  (const Vector<T> &x) { return VectorHelper<T>::abs(x.data()); }
+  template<typename T> static inline Vector<T> reciprocal(const Vector<T> &x) { return VectorHelper<T>::reciprocal(x.data()); }
+  template<typename T> static inline Vector<T> round(const Vector<T> &x) { return VectorHelper<T>::round(x.data()); }
+
+  template<typename T> static inline typename Vector<T>::Mask isfinite(const Vector<T> &x) { return VectorHelper<T>::isFinite(x.data()); }
+  template<typename T> static inline typename Vector<T>::Mask isnan(const Vector<T> &x) { return VectorHelper<T>::isNaN(x.data()); }
+
+#include "forceToRegisters.tcc"
+} // namespace AVX
+} // namespace Vc
+
+#include "vector.tcc"
+#include "math.h"
+#include "undomacros.h"
+
+#endif // AVX_VECTOR_H
diff --git a/Vc/include/Vc/avx/vector.tcc b/Vc/include/Vc/avx/vector.tcc
new file mode 100644 (file)
index 0000000..f7a1f11
--- /dev/null
@@ -0,0 +1,1208 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "limits.h"
+#include "const.h"
+#include "macros.h"
+
+namespace Vc
+{
+ALIGN(64) extern unsigned int RandomState[16];
+
+namespace AVX
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// constants {{{1
+template<typename T> inline ALWAYS_INLINE Vector<T>::Vector(VectorSpecialInitializerZero::ZEnum) : d(HT::zero()) {}
+template<typename T> inline ALWAYS_INLINE Vector<T>::Vector(VectorSpecialInitializerOne::OEnum) : d(HT::one()) {}
+template<typename T> inline ALWAYS_INLINE Vector<T>::Vector(VectorSpecialInitializerIndexesFromZero::IEnum)
+    : d(HV::load(IndexesFromZeroData<T>::address(), Aligned)) {}
+
+template<typename T> inline Vector<T> INTRINSIC CONST Vector<T>::Zero() { return HT::zero(); }
+template<typename T> inline Vector<T> INTRINSIC CONST Vector<T>::One() { return HT::one(); }
+template<typename T> inline Vector<T> INTRINSIC CONST Vector<T>::IndexesFromZero() { return HV::load(IndexesFromZeroData<T>::address(), Aligned); }
+
+template<typename T> template<typename T2> inline ALWAYS_INLINE Vector<T>::Vector(Vector<T2> x)
+    : d(StaticCastHelper<T2, T>::cast(x.data())) {}
+
+template<typename T> inline ALWAYS_INLINE Vector<T>::Vector(EntryType x) : d(HT::set(x)) {}
+template<> inline ALWAYS_INLINE Vector<double>::Vector(EntryType x) : d(_mm256_set1_pd(x)) {}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// load ctors {{{1
+template<typename T> inline ALWAYS_INLINE Vector<T>::Vector(const EntryType *x) { load(x); }
+template<typename T> template<typename A> inline ALWAYS_INLINE Vector<T>::Vector(const EntryType *x, A a) { load(x, a); }
+template<typename T> template<typename OtherT> inline ALWAYS_INLINE Vector<T>::Vector(const OtherT *x) { load(x); }
+template<typename T> template<typename OtherT, typename A> inline ALWAYS_INLINE Vector<T>::Vector(const OtherT *x, A a) { load(x, a); }
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// load member functions {{{1
+template<typename T> inline void INTRINSIC Vector<T>::load(const EntryType *mem)
+{
+    load(mem, Aligned);
+}
+
+template<typename T> template<typename A> inline void INTRINSIC Vector<T>::load(const EntryType *mem, A align)
+{
+    d.v() = HV::load(mem, align);
+}
+
+template<typename T> template<typename OtherT> inline void INTRINSIC Vector<T>::load(const OtherT *mem)
+{
+    load(mem, Aligned);
+}
+
+// LoadHelper {{{2
+template<typename DstT, typename SrcT, typename Flags> struct LoadHelper;
+
+// float {{{2
+template<typename Flags> struct LoadHelper<float, double, Flags> {
+    static __m256 load(const double *mem, Flags f)
+    {
+        return concat(_mm256_cvtpd_ps(VectorHelper<__m256d>::load(&mem[0], f)),
+                      _mm256_cvtpd_ps(VectorHelper<__m256d>::load(&mem[4], f)));
+    }
+};
+template<typename Flags> struct LoadHelper<float, unsigned int, Flags> {
+    static __m256 load(const unsigned int *mem, Flags f)
+    {
+        return StaticCastHelper<unsigned int, float>::cast(VectorHelper<__m256i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<float, int, Flags> {
+    static __m256 load(const int *mem, Flags f)
+    {
+        return StaticCastHelper<int, float>::cast(VectorHelper<__m256i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<float, unsigned short, Flags> {
+    static __m256 load(const unsigned short *mem, Flags f)
+    {
+        return StaticCastHelper<unsigned short, float>::cast(VectorHelper<__m128i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<float, short, Flags> {
+    static __m256 load(const short *mem, Flags f)
+    {
+        return StaticCastHelper<short, float>::cast(VectorHelper<__m128i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<float, unsigned char, Flags> {
+    static __m256 load(const unsigned char *mem, Flags f)
+    {
+        return StaticCastHelper<unsigned int, float>::cast(LoadHelper<unsigned int, unsigned char, Flags>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<float, signed char, Flags> {
+    static __m256 load(const signed char *mem, Flags f)
+    {
+        return StaticCastHelper<int, float>::cast(LoadHelper<int, signed char, Flags>::load(mem, f));
+    }
+};
+
+template<typename SrcT, typename Flags> struct LoadHelper<sfloat, SrcT, Flags> : public LoadHelper<float, SrcT, Flags> {};
+
+// int {{{2
+template<typename Flags> struct LoadHelper<int, unsigned int, Flags> {
+    static __m256i load(const unsigned int *mem, Flags f)
+    {
+        return VectorHelper<__m256i>::load(mem, f);
+    }
+};
+template<typename Flags> struct LoadHelper<int, unsigned short, Flags> {
+    static __m256i load(const unsigned short *mem, Flags f)
+    {
+        return StaticCastHelper<unsigned short, unsigned int>::cast(VectorHelper<__m128i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<int, short, Flags> {
+    static __m256i load(const short *mem, Flags f)
+    {
+        return StaticCastHelper<short, int>::cast(VectorHelper<__m128i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<int, unsigned char, Flags> {
+    static __m256i load(const unsigned char *mem, Flags)
+    {
+        // the only available streaming load loads 16 bytes - twice as much as we need => can't use
+        // it, or we risk an out-of-bounds read and an unaligned load exception
+        const __m128i epu8 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(mem));
+        const __m128i epu16 = _mm_cvtepu8_epi16(epu8);
+        return StaticCastHelper<unsigned short, unsigned int>::cast(epu16);
+    }
+};
+template<typename Flags> struct LoadHelper<int, signed char, Flags> {
+    static __m256i load(const signed char *mem, Flags)
+    {
+        // the only available streaming load loads 16 bytes - twice as much as we need => can't use
+        // it, or we risk an out-of-bounds read and an unaligned load exception
+        const __m128i epi8 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(mem));
+        const __m128i epi16 = _mm_cvtepi8_epi16(epi8);
+        return StaticCastHelper<short, int>::cast(epi16);
+    }
+};
+
+// unsigned int {{{2
+template<typename Flags> struct LoadHelper<unsigned int, unsigned short, Flags> {
+    static __m256i load(const unsigned short *mem, Flags f)
+    {
+        return StaticCastHelper<unsigned short, unsigned int>::cast(VectorHelper<__m128i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<unsigned int, unsigned char, Flags> {
+    static __m256i load(const unsigned char *mem, Flags)
+    {
+        // the only available streaming load loads 16 bytes - twice as much as we need => can't use
+        // it, or we risk an out-of-bounds read and an unaligned load exception
+        const __m128i epu8 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(mem));
+        const __m128i epu16 = _mm_cvtepu8_epi16(epu8);
+        return StaticCastHelper<unsigned short, unsigned int>::cast(epu16);
+    }
+};
+
+// short {{{2
+template<typename Flags> struct LoadHelper<short, unsigned short, Flags> {
+    static __m128i load(const unsigned short *mem, Flags f)
+    {
+        return StaticCastHelper<unsigned short, short>::cast(VectorHelper<__m128i>::load(mem, f));
+    }
+};
+template<typename Flags> struct LoadHelper<short, unsigned char, Flags> {
+    static __m128i load(const unsigned char *mem, Flags)
+    {
+        // the only available streaming load loads 16 bytes - twice as much as we need => can't use
+        // it, or we risk an out-of-bounds read and an unaligned load exception
+        const __m128i epu8 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(mem));
+        return _mm_cvtepu8_epi16(epu8);
+    }
+};
+template<typename Flags> struct LoadHelper<short, signed char, Flags> {
+    static __m128i load(const signed char *mem, Flags)
+    {
+        // the only available streaming load loads 16 bytes - twice as much as we need => can't use
+        // it, or we risk an out-of-bounds read and an unaligned load exception
+        const __m128i epi8 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(mem));
+        return _mm_cvtepi8_epi16(epi8);
+    }
+};
+
+// unsigned short {{{2
+template<typename Flags> struct LoadHelper<unsigned short, unsigned char, Flags> {
+    static __m128i load(const unsigned char *mem, Flags)
+    {
+        // the only available streaming load loads 16 bytes - twice as much as we need => can't use
+        // it, or we risk an out-of-bounds read and an unaligned load exception
+        const __m128i epu8 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(mem));
+        return _mm_cvtepu8_epi16(epu8);
+    }
+};
+
+// general load, implemented via LoadHelper {{{2
+template<typename DstT> template<typename SrcT, typename Flags> inline void INTRINSIC Vector<DstT>::load(const SrcT *x, Flags f)
+{
+    d.v() = LoadHelper<DstT, SrcT, Flags>::load(x, f);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// zeroing {{{1
+template<typename T> inline void INTRINSIC Vector<T>::setZero()
+{
+    data() = HV::zero();
+}
+template<typename T> inline void INTRINSIC Vector<T>::setZero(const Mask &k)
+{
+    data() = HV::andnot_(avx_cast<VectorType>(k.data()), data());
+}
+
+template<> inline void INTRINSIC Vector<double>::setQnan()
+{
+    data() = _mm256_setallone_pd();
+}
+template<> inline void INTRINSIC Vector<double>::setQnan(MaskArg k)
+{
+    data() = _mm256_or_pd(data(), k.dataD());
+}
+template<> inline void INTRINSIC Vector<float>::setQnan()
+{
+    data() = _mm256_setallone_ps();
+}
+template<> inline void INTRINSIC Vector<float>::setQnan(MaskArg k)
+{
+    data() = _mm256_or_ps(data(), k.data());
+}
+template<> inline void INTRINSIC Vector<sfloat>::setQnan()
+{
+    data() = _mm256_setallone_ps();
+}
+template<> inline void INTRINSIC Vector<sfloat>::setQnan(MaskArg k)
+{
+    data() = _mm256_or_ps(data(), k.data());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// stores {{{1
+template<typename T> inline void INTRINSIC Vector<T>::store(EntryType *mem) const
+{
+    HV::store(mem, data(), Aligned);
+}
+template<typename T> inline void INTRINSIC Vector<T>::store(EntryType *mem, const Mask &mask) const
+{
+    HV::store(mem, data(), avx_cast<VectorType>(mask.data()), Aligned);
+}
+template<typename T> template<typename A> inline void INTRINSIC Vector<T>::store(EntryType *mem, A align) const
+{
+    HV::store(mem, data(), align);
+}
+template<typename T> template<typename A> inline void INTRINSIC Vector<T>::store(EntryType *mem, const Mask &mask, A align) const
+{
+    HV::store(mem, data(), avx_cast<VectorType>(mask.data()), align);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// expand/merge 1 float_v <=> 2 double_v          XXX rationale? remove it for release? XXX {{{1
+template<typename T> inline ALWAYS_INLINE FLATTEN Vector<T>::Vector(const Vector<typename HT::ConcatType> *a)
+    : d(a[0])
+{
+}
+template<> inline ALWAYS_INLINE FLATTEN Vector<float>::Vector(const Vector<HT::ConcatType> *a)
+    : d(concat(_mm256_cvtpd_ps(a[0].data()), _mm256_cvtpd_ps(a[1].data())))
+{
+}
+template<> inline ALWAYS_INLINE FLATTEN Vector<short>::Vector(const Vector<HT::ConcatType> *a)
+    : d(_mm_packs_epi32(lo128(a->data()), hi128(a->data())))
+{
+}
+template<> inline ALWAYS_INLINE FLATTEN Vector<unsigned short>::Vector(const Vector<HT::ConcatType> *a)
+    : d(_mm_packus_epi32(lo128(a->data()), hi128(a->data())))
+{
+}
+template<typename T> inline void ALWAYS_INLINE FLATTEN Vector<T>::expand(Vector<typename HT::ConcatType> *x) const
+{
+    x[0] = *this;
+}
+template<> inline void ALWAYS_INLINE FLATTEN Vector<float>::expand(Vector<HT::ConcatType> *x) const
+{
+    x[0].data() = _mm256_cvtps_pd(lo128(d.v()));
+    x[1].data() = _mm256_cvtps_pd(hi128(d.v()));
+}
+template<> inline void ALWAYS_INLINE FLATTEN Vector<short>::expand(Vector<HT::ConcatType> *x) const
+{
+    x[0].data() = concat(_mm_cvtepi16_epi32(d.v()),
+            _mm_cvtepi16_epi32(_mm_unpackhi_epi64(d.v(), d.v())));
+}
+template<> inline void ALWAYS_INLINE FLATTEN Vector<unsigned short>::expand(Vector<HT::ConcatType> *x) const
+{
+    x[0].data() = concat(_mm_cvtepu16_epi32(d.v()),
+            _mm_cvtepu16_epi32(_mm_unpackhi_epi64(d.v(), d.v())));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// swizzles {{{1
+template<typename T> inline const Vector<T> INTRINSIC CONST &Vector<T>::abcd() const { return *this; }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::cdab() const { return Mem::permute<X2, X3, X0, X1>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::badc() const { return Mem::permute<X1, X0, X3, X2>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::aaaa() const { return Mem::permute<X0, X0, X0, X0>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::bbbb() const { return Mem::permute<X1, X1, X1, X1>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::cccc() const { return Mem::permute<X2, X2, X2, X2>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::dddd() const { return Mem::permute<X3, X3, X3, X3>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::bcad() const { return Mem::permute<X1, X2, X0, X3>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::bcda() const { return Mem::permute<X1, X2, X3, X0>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::dabc() const { return Mem::permute<X3, X0, X1, X2>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::acbd() const { return Mem::permute<X0, X2, X1, X3>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::dbca() const { return Mem::permute<X3, X1, X2, X0>(data()); }
+template<typename T> inline const Vector<T> INTRINSIC CONST  Vector<T>::dcba() const { return Mem::permute<X3, X2, X1, X0>(data()); }
+
+template<> inline const double_v INTRINSIC CONST Vector<double>::cdab() const { return Mem::shuffle128<X1, X0>(data(), data()); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::badc() const { return Mem::permute<X1, X0, X3, X2>(data()); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::aaaa() const { const double &tmp = d.m(0); return _mm256_broadcast_sd(&tmp); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::bbbb() const { const double &tmp = d.m(1); return _mm256_broadcast_sd(&tmp); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::cccc() const { const double &tmp = d.m(2); return _mm256_broadcast_sd(&tmp); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::dddd() const { const double &tmp = d.m(3); return _mm256_broadcast_sd(&tmp); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::bcad() const { return Mem::shuffle<X1, Y0, X2, Y3>(Mem::shuffle128<X0, X0>(data(), data()), Mem::shuffle128<X1, X1>(data(), data())); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::bcda() const { return Mem::shuffle<X1, Y0, X3, Y2>(data(), Mem::shuffle128<X1, X0>(data(), data())); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::dabc() const { return Mem::shuffle<X1, Y0, X3, Y2>(Mem::shuffle128<X1, X0>(data(), data()), data()); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::acbd() const { return Mem::shuffle<X0, Y0, X3, Y3>(Mem::shuffle128<X0, X0>(data(), data()), Mem::shuffle128<X1, X1>(data(), data())); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::dbca() const { return Mem::shuffle<X1, Y1, X2, Y2>(Mem::shuffle128<X1, X1>(data(), data()), Mem::shuffle128<X0, X0>(data(), data())); }
+template<> inline const double_v INTRINSIC CONST Vector<double>::dcba() const { return cdab().badc(); }
+
+#define VC_SWIZZLES_16BIT_IMPL(T) \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::cdab() const { return Mem::permute<X2, X3, X0, X1, X6, X7, X4, X5>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::badc() const { return Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::aaaa() const { return Mem::permute<X0, X0, X0, X0, X4, X4, X4, X4>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::bbbb() const { return Mem::permute<X1, X1, X1, X1, X5, X5, X5, X5>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::cccc() const { return Mem::permute<X2, X2, X2, X2, X6, X6, X6, X6>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::dddd() const { return Mem::permute<X3, X3, X3, X3, X7, X7, X7, X7>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::bcad() const { return Mem::permute<X1, X2, X0, X3, X5, X6, X4, X7>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::bcda() const { return Mem::permute<X1, X2, X3, X0, X5, X6, X7, X4>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::dabc() const { return Mem::permute<X3, X0, X1, X2, X7, X4, X5, X6>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::acbd() const { return Mem::permute<X0, X2, X1, X3, X4, X6, X5, X7>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::dbca() const { return Mem::permute<X3, X1, X2, X0, X7, X5, X6, X4>(data()); } \
+template<> inline const Vector<T> INTRINSIC CONST Vector<T>::dcba() const { return Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(data()); }
+VC_SWIZZLES_16BIT_IMPL(short)
+VC_SWIZZLES_16BIT_IMPL(unsigned short)
+#undef VC_SWIZZLES_16BIT_IMPL
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// division {{{1
+template<typename T> inline Vector<T> &Vector<T>::operator/=(EntryType x)
+{
+    if (HasVectorDivision) {
+        return operator/=(Vector<T>(x));
+    }
+    for_all_vector_entries(i,
+            d.m(i) /= x;
+            );
+    return *this;
+}
+template<typename T> template<typename TT> inline PURE VC_EXACT_TYPE(TT, typename DetermineEntryType<T>::Type, Vector<T>) Vector<T>::operator/(TT x) const
+{
+    if (HasVectorDivision) {
+        return operator/(Vector<T>(x));
+    }
+    Vector<T> r;
+    for_all_vector_entries(i,
+            r.d.m(i) = d.m(i) / x;
+            );
+    return r;
+}
+// per default fall back to scalar division
+template<typename T> inline Vector<T> &Vector<T>::operator/=(const Vector<T> &x)
+{
+    for_all_vector_entries(i,
+            d.m(i) /= x.d.m(i);
+            );
+    return *this;
+}
+
+template<typename T> inline Vector<T> PURE Vector<T>::operator/(const Vector<T> &x) const
+{
+    Vector<T> r;
+    for_all_vector_entries(i,
+            r.d.m(i) = d.m(i) / x.d.m(i);
+            );
+    return r;
+}
+// specialize division on type
+static inline __m256i INTRINSIC CONST divInt(__m256i a, __m256i b) {
+    const __m256d lo1 = _mm256_cvtepi32_pd(lo128(a));
+    const __m256d lo2 = _mm256_cvtepi32_pd(lo128(b));
+    const __m256d hi1 = _mm256_cvtepi32_pd(hi128(a));
+    const __m256d hi2 = _mm256_cvtepi32_pd(hi128(b));
+    return concat(
+            _mm256_cvttpd_epi32(_mm256_div_pd(lo1, lo2)),
+            _mm256_cvttpd_epi32(_mm256_div_pd(hi1, hi2))
+            );
+}
+template<> inline Vector<int> &Vector<int>::operator/=(const Vector<int> &x)
+{
+    d.v() = divInt(d.v(), x.d.v());
+    return *this;
+}
+template<> inline Vector<int> PURE Vector<int>::operator/(const Vector<int> &x) const
+{
+    return divInt(d.v(), x.d.v());
+}
+static inline __m256i CONST divUInt(__m256i a, __m256i b) {
+    __m256d loa = _mm256_cvtepi32_pd(lo128(a));
+    __m256d hia = _mm256_cvtepi32_pd(hi128(a));
+    __m256d lob = _mm256_cvtepi32_pd(lo128(b));
+    __m256d hib = _mm256_cvtepi32_pd(hi128(b));
+    // if a >= 2^31 then after conversion to double it will contain a negative number (i.e. a-2^32)
+    // to get the right number back we have to add 2^32 where a >= 2^31
+    loa = _mm256_add_pd(loa, _mm256_and_pd(_mm256_cmp_pd(loa, _mm256_setzero_pd(), _CMP_LT_OS), _mm256_set1_pd(4294967296.)));
+    hia = _mm256_add_pd(hia, _mm256_and_pd(_mm256_cmp_pd(hia, _mm256_setzero_pd(), _CMP_LT_OS), _mm256_set1_pd(4294967296.)));
+    // we don't do the same for b because division by b >= 2^31 should be a seldom corner case and
+    // we rather want the standard stuff fast
+    //
+    // there is one remaining problem: a >= 2^31 and b == 1
+    // in that case the return value would be 2^31
+    return avx_cast<__m256i>(_mm256_blendv_ps(avx_cast<__m256>(concat(
+                        _mm256_cvttpd_epi32(_mm256_div_pd(loa, lob)),
+                        _mm256_cvttpd_epi32(_mm256_div_pd(hia, hib))
+                        )), avx_cast<__m256>(a), avx_cast<__m256>(concat(
+                            _mm_cmpeq_epi32(lo128(b), _mm_setone_epi32()),
+                            _mm_cmpeq_epi32(hi128(b), _mm_setone_epi32())))));
+}
+template<> inline Vector<unsigned int> ALWAYS_INLINE &Vector<unsigned int>::operator/=(const Vector<unsigned int> &x)
+{
+    d.v() = divUInt(d.v(), x.d.v());
+    return *this;
+}
+template<> inline Vector<unsigned int> ALWAYS_INLINE PURE Vector<unsigned int>::operator/(const Vector<unsigned int> &x) const
+{
+    return divUInt(d.v(), x.d.v());
+}
+template<typename T> static inline __m128i CONST divShort(__m128i a, __m128i b)
+{
+    const __m256 r = _mm256_div_ps(StaticCastHelper<T, float>::cast(a),
+            StaticCastHelper<T, float>::cast(b));
+    return StaticCastHelper<float, T>::cast(r);
+}
+template<> inline Vector<short> ALWAYS_INLINE &Vector<short>::operator/=(const Vector<short> &x)
+{
+    d.v() = divShort<short>(d.v(), x.d.v());
+    return *this;
+}
+template<> inline Vector<short> ALWAYS_INLINE PURE Vector<short>::operator/(const Vector<short> &x) const
+{
+    return divShort<short>(d.v(), x.d.v());
+}
+template<> inline Vector<unsigned short> ALWAYS_INLINE &Vector<unsigned short>::operator/=(const Vector<unsigned short> &x)
+{
+    d.v() = divShort<unsigned short>(d.v(), x.d.v());
+    return *this;
+}
+template<> inline Vector<unsigned short> ALWAYS_INLINE PURE Vector<unsigned short>::operator/(const Vector<unsigned short> &x) const
+{
+    return divShort<unsigned short>(d.v(), x.d.v());
+}
+template<> inline Vector<float> INTRINSIC &Vector<float>::operator/=(const Vector<float> &x)
+{
+    d.v() = _mm256_div_ps(d.v(), x.d.v());
+    return *this;
+}
+template<> inline Vector<float> INTRINSIC PURE Vector<float>::operator/(const Vector<float> &x) const
+{
+    return _mm256_div_ps(d.v(), x.d.v());
+}
+template<> inline Vector<double> INTRINSIC &Vector<double>::operator/=(const Vector<double> &x)
+{
+    d.v() = _mm256_div_pd(d.v(), x.d.v());
+    return *this;
+}
+template<> inline Vector<double> INTRINSIC PURE Vector<double>::operator/(const Vector<double> &x) const
+{
+    return _mm256_div_pd(d.v(), x.d.v());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// integer ops {{{1
+#define OP_IMPL(T, symbol) \
+template<> inline Vector<T> &Vector<T>::operator symbol##=(AsArg x) \
+{ \
+    for_all_vector_entries(i, d.m(i) symbol##= x.d.m(i); ); \
+    return *this; \
+} \
+template<> inline Vector<T>  Vector<T>::operator symbol(AsArg x) const \
+{ \
+    Vector<T> r; \
+    for_all_vector_entries(i, r.d.m(i) = d.m(i) symbol x.d.m(i); ); \
+    return r; \
+}
+OP_IMPL(int, <<)
+OP_IMPL(int, >>)
+OP_IMPL(unsigned int, <<)
+OP_IMPL(unsigned int, >>)
+OP_IMPL(short, <<)
+OP_IMPL(short, >>)
+OP_IMPL(unsigned short, <<)
+OP_IMPL(unsigned short, >>)
+#undef OP_IMPL
+
+template<typename T> inline Vector<T> &Vector<T>::operator>>=(int shift) {
+    d.v() = VectorHelper<T>::shiftRight(d.v(), shift);
+    return *static_cast<Vector<T> *>(this);
+}
+template<typename T> inline Vector<T> Vector<T>::operator>>(int shift) const {
+    return VectorHelper<T>::shiftRight(d.v(), shift);
+}
+template<typename T> inline Vector<T> &Vector<T>::operator<<=(int shift) {
+    d.v() = VectorHelper<T>::shiftLeft(d.v(), shift);
+    return *static_cast<Vector<T> *>(this);
+}
+template<typename T> inline Vector<T> Vector<T>::operator<<(int shift) const {
+    return VectorHelper<T>::shiftLeft(d.v(), shift);
+}
+
+#define OP_IMPL(T, symbol, fun) \
+  template<> inline Vector<T> &Vector<T>::operator symbol##=(AsArg x) { d.v() = HV::fun(d.v(), x.d.v()); return *this; } \
+  template<> inline Vector<T>  Vector<T>::operator symbol(AsArg x) const { return Vector<T>(HV::fun(d.v(), x.d.v())); }
+  OP_IMPL(int, &, and_)
+  OP_IMPL(int, |, or_)
+  OP_IMPL(int, ^, xor_)
+  OP_IMPL(unsigned int, &, and_)
+  OP_IMPL(unsigned int, |, or_)
+  OP_IMPL(unsigned int, ^, xor_)
+  OP_IMPL(short, &, and_)
+  OP_IMPL(short, |, or_)
+  OP_IMPL(short, ^, xor_)
+  OP_IMPL(unsigned short, &, and_)
+  OP_IMPL(unsigned short, |, or_)
+  OP_IMPL(unsigned short, ^, xor_)
+  OP_IMPL(float, &, and_)
+  OP_IMPL(float, |, or_)
+  OP_IMPL(float, ^, xor_)
+  OP_IMPL(sfloat, &, and_)
+  OP_IMPL(sfloat, |, or_)
+  OP_IMPL(sfloat, ^, xor_)
+  OP_IMPL(double, &, and_)
+  OP_IMPL(double, |, or_)
+  OP_IMPL(double, ^, xor_)
+#undef OP_IMPL
+
+// operators {{{1
+#include "../common/operators.h"
+// gathers {{{1
+// Better implementation (hopefully) with _mm256_set_
+//X template<typename T> template<typename Index> Vector<T>::Vector(const EntryType *mem, const Index *indexes)
+//X {
+//X     for_all_vector_entries(int i,
+//X             d.m(i) = mem[indexes[i]];
+//X             );
+//X }
+template<typename T> template<typename IndexT> inline ALWAYS_INLINE Vector<T>::Vector(const EntryType *mem, const IndexT *indexes)
+{
+    gather(mem, indexes);
+}
+template<typename T> template<typename IndexT> inline ALWAYS_INLINE Vector<T>::Vector(const EntryType *mem, Vector<IndexT> indexes)
+{
+    gather(mem, indexes);
+}
+
+template<typename T> template<typename IndexT> inline ALWAYS_INLINE Vector<T>::Vector(const EntryType *mem, const IndexT *indexes, MaskArg mask)
+    : d(HT::zero())
+{
+    gather(mem, indexes, mask);
+}
+
+template<typename T> template<typename IndexT> inline ALWAYS_INLINE Vector<T>::Vector(const EntryType *mem, Vector<IndexT> indexes, MaskArg mask)
+    : d(HT::zero())
+{
+    gather(mem, indexes, mask);
+}
+
+template<typename T> template<typename S1, typename IT> inline ALWAYS_INLINE Vector<T>::Vector(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    gather(array, member1, indexes);
+}
+template<typename T> template<typename S1, typename IT> inline ALWAYS_INLINE Vector<T>::Vector(const S1 *array, const EntryType S1::* member1, IT indexes, MaskArg mask)
+    : d(HT::zero())
+{
+    gather(array, member1, indexes, mask);
+}
+template<typename T> template<typename S1, typename S2, typename IT> inline ALWAYS_INLINE Vector<T>::Vector(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    gather(array, member1, member2, indexes);
+}
+template<typename T> template<typename S1, typename S2, typename IT> inline ALWAYS_INLINE Vector<T>::Vector(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes, MaskArg mask)
+    : d(HT::zero())
+{
+    gather(array, member1, member2, indexes, mask);
+}
+template<typename T> template<typename S1, typename IT1, typename IT2> inline ALWAYS_INLINE Vector<T>::Vector(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    gather(array, ptrMember1, outerIndexes, innerIndexes);
+}
+template<typename T> template<typename S1, typename IT1, typename IT2> inline ALWAYS_INLINE Vector<T>::Vector(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes, MaskArg mask)
+    : d(HT::zero())
+{
+    gather(array, ptrMember1, outerIndexes, innerIndexes, mask);
+}
+
+template<typename T, size_t Size> struct IndexSizeChecker { static void check() {} };
+template<typename T, size_t Size> struct IndexSizeChecker<Vector<T>, Size>
+{
+    static void check() {
+        VC_STATIC_ASSERT(Vector<T>::Size >= Size, IndexVector_must_have_greater_or_equal_number_of_entries);
+    }
+};
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<double>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm256_setr_pd(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]]);
+}
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<float>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm256_setr_ps(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]],
+            mem[indexes[4]], mem[indexes[5]], mem[indexes[6]], mem[indexes[7]]);
+}
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<sfloat>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm256_setr_ps(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]],
+            mem[indexes[4]], mem[indexes[5]], mem[indexes[6]], mem[indexes[7]]);
+}
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<int>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm256_setr_epi32(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]],
+            mem[indexes[4]], mem[indexes[5]], mem[indexes[6]], mem[indexes[7]]);
+}
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<unsigned int>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm256_setr_epi32(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]],
+            mem[indexes[4]], mem[indexes[5]], mem[indexes[6]], mem[indexes[7]]);
+}
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<short>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm_setr_epi16(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]],
+            mem[indexes[4]], mem[indexes[5]], mem[indexes[6]], mem[indexes[7]]);
+}
+template<> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<unsigned short>::gather(const EntryType *mem, Index indexes)
+{
+    IndexSizeChecker<Index, Size>::check();
+    d.v() = _mm_setr_epi16(mem[indexes[0]], mem[indexes[1]], mem[indexes[2]], mem[indexes[3]],
+                mem[indexes[4]], mem[indexes[5]], mem[indexes[6]], mem[indexes[7]]);
+}
+
+#ifdef VC_USE_SET_GATHERS
+template<typename T> template<typename IT> inline void ALWAYS_INLINE Vector<T>::gather(const EntryType *mem, Vector<IT> indexes, MaskArg mask)
+{
+    IndexSizeChecker<Vector<IT>, Size>::check();
+    indexes.setZero(!mask);
+    (*this)(mask) = Vector<T>(mem, indexes);
+}
+#endif
+
+#ifdef VC_USE_BSF_GATHERS
+#define VC_MASKED_GATHER                        \
+    int bits = mask.toInt();                    \
+    while (bits) {                              \
+        const int i = _bit_scan_forward(bits);  \
+        bits &= ~(1 << i); /* btr? */           \
+        d.m(i) = ith_value(i);                  \
+    }
+#elif defined(VC_USE_POPCNT_BSF_GATHERS)
+#define VC_MASKED_GATHER                        \
+    unsigned int bits = mask.toInt();           \
+    unsigned int low, high = 0;                 \
+    switch (_mm_popcnt_u32(bits)) {             \
+    case 8:                                     \
+        high = _bit_scan_reverse(bits);         \
+        d.m(high) = ith_value(high);            \
+        high = (1 << high);                     \
+    case 7:                                     \
+        low = _bit_scan_forward(bits);          \
+        bits ^= high | (1 << low);              \
+        d.m(low) = ith_value(low);              \
+    case 6:                                     \
+        high = _bit_scan_reverse(bits);         \
+        d.m(high) = ith_value(high);            \
+        high = (1 << high);                     \
+    case 5:                                     \
+        low = _bit_scan_forward(bits);          \
+        bits ^= high | (1 << low);              \
+        d.m(low) = ith_value(low);              \
+    case 4:                                     \
+        high = _bit_scan_reverse(bits);         \
+        d.m(high) = ith_value(high);            \
+        high = (1 << high);                     \
+    case 3:                                     \
+        low = _bit_scan_forward(bits);          \
+        bits ^= high | (1 << low);              \
+        d.m(low) = ith_value(low);              \
+    case 2:                                     \
+        high = _bit_scan_reverse(bits);         \
+        d.m(high) = ith_value(high);            \
+    case 1:                                     \
+        low = _bit_scan_forward(bits);          \
+        d.m(low) = ith_value(low);              \
+    case 0:                                     \
+        break;                                  \
+    }
+#else
+#define VC_MASKED_GATHER                        \
+    if (mask.isEmpty()) {                       \
+        return;                                 \
+    }                                           \
+    for_all_vector_entries(i,                   \
+            if (mask[i]) d.m(i) = ith_value(i); \
+            );
+#endif
+
+template<typename T> template<typename Index>
+inline void INTRINSIC Vector<T>::gather(const EntryType *mem, Index indexes, MaskArg mask)
+{
+    IndexSizeChecker<Index, Size>::check();
+#define ith_value(_i_) (mem[indexes[_i_]])
+    VC_MASKED_GATHER
+#undef ith_value
+}
+
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<double>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_pd(array[indexes[0]].*(member1), array[indexes[1]].*(member1),
+            array[indexes[2]].*(member1), array[indexes[3]].*(member1));
+}
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<float>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_ps(array[indexes[0]].*(member1), array[indexes[1]].*(member1), array[indexes[2]].*(member1),
+            array[indexes[3]].*(member1), array[indexes[4]].*(member1), array[indexes[5]].*(member1),
+            array[indexes[6]].*(member1), array[indexes[7]].*(member1));
+}
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<sfloat>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_ps(array[indexes[0]].*(member1), array[indexes[1]].*(member1), array[indexes[2]].*(member1),
+            array[indexes[3]].*(member1), array[indexes[4]].*(member1), array[indexes[5]].*(member1),
+            array[indexes[6]].*(member1), array[indexes[7]].*(member1));
+}
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<int>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_epi32(array[indexes[0]].*(member1), array[indexes[1]].*(member1), array[indexes[2]].*(member1),
+            array[indexes[3]].*(member1), array[indexes[4]].*(member1), array[indexes[5]].*(member1),
+            array[indexes[6]].*(member1), array[indexes[7]].*(member1));
+}
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<unsigned int>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_epi32(array[indexes[0]].*(member1), array[indexes[1]].*(member1), array[indexes[2]].*(member1),
+            array[indexes[3]].*(member1), array[indexes[4]].*(member1), array[indexes[5]].*(member1),
+            array[indexes[6]].*(member1), array[indexes[7]].*(member1));
+}
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<short>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm_setr_epi16(array[indexes[0]].*(member1), array[indexes[1]].*(member1), array[indexes[2]].*(member1),
+            array[indexes[3]].*(member1), array[indexes[4]].*(member1), array[indexes[5]].*(member1),
+            array[indexes[6]].*(member1), array[indexes[7]].*(member1));
+}
+template<> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<unsigned short>::gather(const S1 *array, const EntryType S1::* member1, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm_setr_epi16(array[indexes[0]].*(member1), array[indexes[1]].*(member1), array[indexes[2]].*(member1),
+            array[indexes[3]].*(member1), array[indexes[4]].*(member1), array[indexes[5]].*(member1),
+            array[indexes[6]].*(member1), array[indexes[7]].*(member1));
+}
+template<typename T> template<typename S1, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<T>::gather(const S1 *array, const EntryType S1::* member1, IT indexes, MaskArg mask)
+{
+    IndexSizeChecker<IT, Size>::check();
+#define ith_value(_i_) (array[indexes[_i_]].*(member1))
+    VC_MASKED_GATHER
+#undef ith_value
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<double>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_pd(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2),
+            array[indexes[2]].*(member1).*(member2), array[indexes[3]].*(member1).*(member2));
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<float>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_ps(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2), array[indexes[2]].*(member1).*(member2),
+            array[indexes[3]].*(member1).*(member2), array[indexes[4]].*(member1).*(member2), array[indexes[5]].*(member1).*(member2),
+            array[indexes[6]].*(member1).*(member2), array[indexes[7]].*(member1).*(member2));
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<sfloat>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_ps(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2), array[indexes[2]].*(member1).*(member2),
+            array[indexes[3]].*(member1).*(member2), array[indexes[4]].*(member1).*(member2), array[indexes[5]].*(member1).*(member2),
+            array[indexes[6]].*(member1).*(member2), array[indexes[7]].*(member1).*(member2));
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<int>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_epi32(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2), array[indexes[2]].*(member1).*(member2),
+            array[indexes[3]].*(member1).*(member2), array[indexes[4]].*(member1).*(member2), array[indexes[5]].*(member1).*(member2),
+            array[indexes[6]].*(member1).*(member2), array[indexes[7]].*(member1).*(member2));
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<unsigned int>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm256_setr_epi32(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2), array[indexes[2]].*(member1).*(member2),
+            array[indexes[3]].*(member1).*(member2), array[indexes[4]].*(member1).*(member2), array[indexes[5]].*(member1).*(member2),
+            array[indexes[6]].*(member1).*(member2), array[indexes[7]].*(member1).*(member2));
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<short>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm_setr_epi16(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2), array[indexes[2]].*(member1).*(member2),
+            array[indexes[3]].*(member1).*(member2), array[indexes[4]].*(member1).*(member2), array[indexes[5]].*(member1).*(member2),
+            array[indexes[6]].*(member1).*(member2), array[indexes[7]].*(member1).*(member2));
+}
+template<> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<unsigned short>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes)
+{
+    IndexSizeChecker<IT, Size>::check();
+    d.v() = _mm_setr_epi16(array[indexes[0]].*(member1).*(member2), array[indexes[1]].*(member1).*(member2), array[indexes[2]].*(member1).*(member2),
+            array[indexes[3]].*(member1).*(member2), array[indexes[4]].*(member1).*(member2), array[indexes[5]].*(member1).*(member2),
+            array[indexes[6]].*(member1).*(member2), array[indexes[7]].*(member1).*(member2));
+}
+template<typename T> template<typename S1, typename S2, typename IT>
+inline void ALWAYS_INLINE FLATTEN Vector<T>::gather(const S1 *array, const S2 S1::* member1, const EntryType S2::* member2, IT indexes, MaskArg mask)
+{
+    IndexSizeChecker<IT, Size>::check();
+#define ith_value(_i_) (array[indexes[_i_]].*(member1).*(member2))
+    VC_MASKED_GATHER
+#undef ith_value
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<double>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm256_setr_pd((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]]);
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<float>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm256_setr_ps((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]],
+            (array[outerIndexes[4]].*(ptrMember1))[innerIndexes[4]], (array[outerIndexes[5]].*(ptrMember1))[innerIndexes[5]],
+            (array[outerIndexes[6]].*(ptrMember1))[innerIndexes[6]], (array[outerIndexes[7]].*(ptrMember1))[innerIndexes[7]]);
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<sfloat>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm256_setr_ps((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]],
+            (array[outerIndexes[4]].*(ptrMember1))[innerIndexes[4]], (array[outerIndexes[5]].*(ptrMember1))[innerIndexes[5]],
+            (array[outerIndexes[6]].*(ptrMember1))[innerIndexes[6]], (array[outerIndexes[7]].*(ptrMember1))[innerIndexes[7]]);
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<int>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm256_setr_epi32((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]],
+            (array[outerIndexes[4]].*(ptrMember1))[innerIndexes[4]], (array[outerIndexes[5]].*(ptrMember1))[innerIndexes[5]],
+            (array[outerIndexes[6]].*(ptrMember1))[innerIndexes[6]], (array[outerIndexes[7]].*(ptrMember1))[innerIndexes[7]]);
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<unsigned int>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm256_setr_epi32((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]],
+            (array[outerIndexes[4]].*(ptrMember1))[innerIndexes[4]], (array[outerIndexes[5]].*(ptrMember1))[innerIndexes[5]],
+            (array[outerIndexes[6]].*(ptrMember1))[innerIndexes[6]], (array[outerIndexes[7]].*(ptrMember1))[innerIndexes[7]]);
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<short>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm_setr_epi16((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]],
+            (array[outerIndexes[4]].*(ptrMember1))[innerIndexes[4]], (array[outerIndexes[5]].*(ptrMember1))[innerIndexes[5]],
+            (array[outerIndexes[6]].*(ptrMember1))[innerIndexes[6]], (array[outerIndexes[7]].*(ptrMember1))[innerIndexes[7]]);
+}
+template<> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<unsigned short>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+    d.v() = _mm_setr_epi16((array[outerIndexes[0]].*(ptrMember1))[innerIndexes[0]], (array[outerIndexes[1]].*(ptrMember1))[innerIndexes[1]],
+            (array[outerIndexes[2]].*(ptrMember1))[innerIndexes[2]], (array[outerIndexes[3]].*(ptrMember1))[innerIndexes[3]],
+            (array[outerIndexes[4]].*(ptrMember1))[innerIndexes[4]], (array[outerIndexes[5]].*(ptrMember1))[innerIndexes[5]],
+            (array[outerIndexes[6]].*(ptrMember1))[innerIndexes[6]], (array[outerIndexes[7]].*(ptrMember1))[innerIndexes[7]]);
+}
+template<typename T> template<typename S1, typename IT1, typename IT2>
+inline void ALWAYS_INLINE FLATTEN Vector<T>::gather(const S1 *array, const EntryType *const S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes, MaskArg mask)
+{
+    IndexSizeChecker<IT1, Size>::check();
+    IndexSizeChecker<IT2, Size>::check();
+#define ith_value(_i_) (array[outerIndexes[_i_]].*(ptrMember1))[innerIndexes[_i_]]
+    VC_MASKED_GATHER
+#undef ith_value
+}
+
+#undef VC_MASKED_GATHER
+#ifdef VC_USE_BSF_SCATTERS
+#define VC_MASKED_SCATTER                       \
+    int bits = mask.toInt();                    \
+    while (bits) {                              \
+        const int i = _bit_scan_forward(bits);  \
+        bits ^= (1 << i); /* btr? */            \
+        ith_value(i) = d.m(i);                  \
+    }
+#elif defined(VC_USE_POPCNT_BSF_SCATTERS)
+#define VC_MASKED_SCATTER                       \
+    unsigned int bits = mask.toInt();           \
+    unsigned int low, high = 0;                 \
+    switch (_mm_popcnt_u32(bits)) {             \
+    case 8:                                     \
+        high = _bit_scan_reverse(bits);         \
+        ith_value(high) = d.m(high);            \
+        high = (1 << high);                     \
+    case 7:                                     \
+        low = _bit_scan_forward(bits);          \
+        bits ^= high | (1 << low);              \
+        ith_value(low) = d.m(low);              \
+    case 6:                                     \
+        high = _bit_scan_reverse(bits);         \
+        ith_value(high) = d.m(high);            \
+        high = (1 << high);                     \
+    case 5:                                     \
+        low = _bit_scan_forward(bits);          \
+        bits ^= high | (1 << low);              \
+        ith_value(low) = d.m(low);              \
+    case 4:                                     \
+        high = _bit_scan_reverse(bits);         \
+        ith_value(high) = d.m(high);            \
+        high = (1 << high);                     \
+    case 3:                                     \
+        low = _bit_scan_forward(bits);          \
+        bits ^= high | (1 << low);              \
+        ith_value(low) = d.m(low);              \
+    case 2:                                     \
+        high = _bit_scan_reverse(bits);         \
+        ith_value(high) = d.m(high);            \
+    case 1:                                     \
+        low = _bit_scan_forward(bits);          \
+        ith_value(low) = d.m(low);              \
+    case 0:                                     \
+        break;                                  \
+    }
+#else
+#define VC_MASKED_SCATTER                       \
+    if (mask.isEmpty()) {                       \
+        return;                                 \
+    }                                           \
+    for_all_vector_entries(i,                   \
+            if (mask[i]) ith_value(i) = d.m(i); \
+            );
+#endif
+
+template<typename T> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(EntryType *mem, Index indexes) const
+{
+    for_all_vector_entries(i,
+            mem[indexes[i]] = d.m(i);
+            );
+}
+template<typename T> template<typename Index> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(EntryType *mem, Index indexes, MaskArg mask) const
+{
+#define ith_value(_i_) mem[indexes[_i_]]
+    VC_MASKED_SCATTER
+#undef ith_value
+}
+template<typename T> template<typename S1, typename IT> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(S1 *array, EntryType S1::* member1, IT indexes) const
+{
+    for_all_vector_entries(i,
+            array[indexes[i]].*(member1) = d.m(i);
+            );
+}
+template<typename T> template<typename S1, typename IT> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(S1 *array, EntryType S1::* member1, IT indexes, MaskArg mask) const
+{
+#define ith_value(_i_) array[indexes[_i_]].*(member1)
+    VC_MASKED_SCATTER
+#undef ith_value
+}
+template<typename T> template<typename S1, typename S2, typename IT> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(S1 *array, S2 S1::* member1, EntryType S2::* member2, IT indexes) const
+{
+    for_all_vector_entries(i,
+            array[indexes[i]].*(member1).*(member2) = d.m(i);
+            );
+}
+template<typename T> template<typename S1, typename S2, typename IT> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(S1 *array, S2 S1::* member1, EntryType S2::* member2, IT indexes, MaskArg mask) const
+{
+#define ith_value(_i_) array[indexes[_i_]].*(member1).*(member2)
+    VC_MASKED_SCATTER
+#undef ith_value
+}
+template<typename T> template<typename S1, typename IT1, typename IT2> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(S1 *array, EntryType *S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes) const
+{
+    for_all_vector_entries(i,
+            (array[innerIndexes[i]].*(ptrMember1))[outerIndexes[i]] = d.m(i);
+            );
+}
+template<typename T> template<typename S1, typename IT1, typename IT2> inline void ALWAYS_INLINE FLATTEN Vector<T>::scatter(S1 *array, EntryType *S1::* ptrMember1, IT1 outerIndexes, IT2 innerIndexes, MaskArg mask) const
+{
+#define ith_value(_i_) (array[outerIndexes[_i_]].*(ptrMember1))[innerIndexes[_i_]]
+    VC_MASKED_SCATTER
+#undef ith_value
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// operator- {{{1
+template<> inline Vector<double> PURE ALWAYS_INLINE FLATTEN Vector<double>::operator-() const
+{
+    return _mm256_xor_pd(d.v(), _mm256_setsignmask_pd());
+}
+template<> inline Vector<float> PURE ALWAYS_INLINE FLATTEN Vector<float>::operator-() const
+{
+    return _mm256_xor_ps(d.v(), _mm256_setsignmask_ps());
+}
+template<> inline Vector<sfloat> PURE ALWAYS_INLINE FLATTEN Vector<sfloat>::operator-() const
+{
+    return _mm256_xor_ps(d.v(), _mm256_setsignmask_ps());
+}
+template<> inline Vector<int> PURE ALWAYS_INLINE FLATTEN Vector<int>::operator-() const
+{
+    return _mm256_sign_epi32(d.v(), _mm256_setallone_si256());
+}
+template<> inline Vector<int> PURE ALWAYS_INLINE FLATTEN Vector<unsigned int>::operator-() const
+{
+    return _mm256_sign_epi32(d.v(), _mm256_setallone_si256());
+}
+template<> inline Vector<short> PURE ALWAYS_INLINE FLATTEN Vector<short>::operator-() const
+{
+    return _mm_sign_epi16(d.v(), _mm_setallone_si128());
+}
+template<> inline Vector<short> PURE ALWAYS_INLINE FLATTEN Vector<unsigned short>::operator-() const
+{
+    return _mm_sign_epi16(d.v(), _mm_setallone_si128());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// horizontal ops {{{1
+template<typename T> inline typename Vector<T>::EntryType Vector<T>::min(MaskArg m) const
+{
+    Vector<T> tmp = std::numeric_limits<Vector<T> >::max();
+    tmp(m) = *this;
+    return tmp.min();
+}
+template<typename T> inline typename Vector<T>::EntryType Vector<T>::max(MaskArg m) const
+{
+    Vector<T> tmp = std::numeric_limits<Vector<T> >::min();
+    tmp(m) = *this;
+    return tmp.max();
+}
+template<typename T> inline typename Vector<T>::EntryType Vector<T>::product(MaskArg m) const
+{
+    Vector<T> tmp(VectorSpecialInitializerOne::One);
+    tmp(m) = *this;
+    return tmp.product();
+}
+template<typename T> inline typename Vector<T>::EntryType Vector<T>::sum(MaskArg m) const
+{
+    Vector<T> tmp(VectorSpecialInitializerZero::Zero);
+    tmp(m) = *this;
+    return tmp.sum();
+}//}}}
+// copySign {{{1
+template<> inline Vector<float> INTRINSIC Vector<float>::copySign(Vector<float>::AsArg reference) const
+{
+    return _mm256_or_ps(
+            _mm256_and_ps(reference.d.v(), _mm256_setsignmask_ps()),
+            _mm256_and_ps(d.v(), _mm256_setabsmask_ps())
+            );
+}
+template<> inline Vector<sfloat> INTRINSIC Vector<sfloat>::copySign(Vector<sfloat>::AsArg reference) const
+{
+    return _mm256_or_ps(
+            _mm256_and_ps(reference.d.v(), _mm256_setsignmask_ps()),
+            _mm256_and_ps(d.v(), _mm256_setabsmask_ps())
+            );
+}
+template<> inline Vector<double> INTRINSIC Vector<double>::copySign(Vector<double>::AsArg reference) const
+{
+    return _mm256_or_pd(
+            _mm256_and_pd(reference.d.v(), _mm256_setsignmask_pd()),
+            _mm256_and_pd(d.v(), _mm256_setabsmask_pd())
+            );
+}//}}}1
+// exponent {{{1
+template<> inline Vector<float> INTRINSIC Vector<float>::exponent() const
+{
+    VC_ASSERT((*this > 0.f).isFull());
+    __m128i tmp0 = _mm_srli_epi32(avx_cast<__m128i>(d.v()), 23);
+    __m128i tmp1 = _mm_srli_epi32(avx_cast<__m128i>(hi128(d.v())), 23);
+    tmp0 = _mm_sub_epi32(tmp0, _mm_set1_epi32(0x7f));
+    tmp1 = _mm_sub_epi32(tmp1, _mm_set1_epi32(0x7f));
+    return _mm256_cvtepi32_ps(concat(tmp0, tmp1));
+}
+template<> inline Vector<sfloat> INTRINSIC Vector<sfloat>::exponent() const
+{
+    VC_ASSERT((*this > 0.f).isFull());
+    __m128i tmp0 = _mm_srli_epi32(avx_cast<__m128i>(d.v()), 23);
+    __m128i tmp1 = _mm_srli_epi32(avx_cast<__m128i>(hi128(d.v())), 23);
+    tmp0 = _mm_sub_epi32(tmp0, _mm_set1_epi32(0x7f));
+    tmp1 = _mm_sub_epi32(tmp1, _mm_set1_epi32(0x7f));
+    return _mm256_cvtepi32_ps(concat(tmp0, tmp1));
+}
+template<> inline Vector<double> INTRINSIC Vector<double>::exponent() const
+{
+    VC_ASSERT((*this > 0.).isFull());
+    __m128i tmp0 = _mm_srli_epi64(avx_cast<__m128i>(d.v()), 52);
+    __m128i tmp1 = _mm_srli_epi64(avx_cast<__m128i>(hi128(d.v())), 52);
+    tmp0 = _mm_sub_epi32(tmp0, _mm_set1_epi32(0x3ff));
+    tmp1 = _mm_sub_epi32(tmp1, _mm_set1_epi32(0x3ff));
+    return _mm256_cvtepi32_pd(avx_cast<__m128i>(Mem::shuffle<X0, X2, Y0, Y2>(avx_cast<__m128>(tmp0), avx_cast<__m128>(tmp1))));
+}
+// }}}1
+// Random {{{1
+static inline ALWAYS_INLINE void _doRandomStep(Vector<unsigned int> &state0,
+        Vector<unsigned int> &state1)
+{
+    state0.load(&Vc::RandomState[0]);
+    state1.load(&Vc::RandomState[uint_v::Size]);
+    (state1 * 0xdeece66du + 11).store(&Vc::RandomState[uint_v::Size]);
+    uint_v(_mm256_xor_si256((state0 * 0xdeece66du + 11).data(), _mm256_srli_epi32(state1.data(), 16))).store(&Vc::RandomState[0]);
+}
+
+template<typename T> inline ALWAYS_INLINE Vector<T> Vector<T>::Random()
+{
+    Vector<unsigned int> state0, state1;
+    _doRandomStep(state0, state1);
+    return state0.reinterpretCast<Vector<T> >();
+}
+
+template<> inline ALWAYS_INLINE Vector<float> Vector<float>::Random()
+{
+    Vector<unsigned int> state0, state1;
+    _doRandomStep(state0, state1);
+    return HT::sub(HV::or_(_cast(_mm256_srli_epi32(state0.data(), 2)), HT::one()), HT::one());
+}
+
+template<> inline ALWAYS_INLINE Vector<sfloat> Vector<sfloat>::Random()
+{
+    Vector<unsigned int> state0, state1;
+    _doRandomStep(state0, state1);
+    return HT::sub(HV::or_(_cast(_mm256_srli_epi32(state0.data(), 2)), HT::one()), HT::one());
+}
+
+template<> inline ALWAYS_INLINE Vector<double> Vector<double>::Random()
+{
+    const __m256i state = VectorHelper<__m256i>::load(&Vc::RandomState[0], Vc::Aligned);
+    for (size_t k = 0; k < 8; k += 2) {
+        typedef unsigned long long uint64 MAY_ALIAS;
+        const uint64 stateX = *reinterpret_cast<const uint64 *>(&Vc::RandomState[k]);
+        *reinterpret_cast<uint64 *>(&Vc::RandomState[k]) = (stateX * 0x5deece66dull + 11);
+    }
+    return (Vector<double>(_cast(_mm256_srli_epi64(state, 12))) | One()) - One();
+}
+// }}}1
+} // namespace AVX
+} // namespace Vc
+
+#include "undomacros.h"
+
+// vim: foldmethod=marker
diff --git a/Vc/include/Vc/avx/vectorhelper.h b/Vc/include/Vc/avx/vectorhelper.h
new file mode 100644 (file)
index 0000000..ed83c6f
--- /dev/null
@@ -0,0 +1,667 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AVX_VECTORHELPER_H
+#define AVX_VECTORHELPER_H
+
+#include <limits>
+#include "types.h"
+#include "intrinsics.h"
+#include "casts.h"
+
+namespace Vc
+{
+namespace AVX
+{
+#define OP0(name, code) static inline VectorType name() { return code; }
+#define OP1(name, code) static inline VectorType name(const VectorType &a) { return code; }
+#define OP2(name, code) static inline VectorType name(const VectorType &a, const VectorType &b) { return code; }
+#define OP3(name, code) static inline VectorType name(const VectorType &a, const VectorType &b, const VectorType &c) { return code; }
+
+        template<> struct VectorHelper<_M256>
+        {
+            typedef _M256 VectorType;
+            template<typename A> static VectorType load(const float *x, A) PURE;
+            static void store(float *mem, const VectorType x, AlignedFlag);
+            static void store(float *mem, const VectorType x, UnalignedFlag);
+            static void store(float *mem, const VectorType x, StreamingAndAlignedFlag);
+            static void store(float *mem, const VectorType x, StreamingAndUnalignedFlag);
+            static void store(float *mem, const VectorType x, const VectorType m, AlignedFlag);
+            static void store(float *mem, const VectorType x, const VectorType m, UnalignedFlag);
+            static void store(float *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag);
+            static void store(float *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag);
+
+            static VectorType cdab(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(2, 3, 0, 1)); }
+            static VectorType badc(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2)); }
+            static VectorType aaaa(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(0, 0, 0, 0)); }
+            static VectorType bbbb(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(1, 1, 1, 1)); }
+            static VectorType cccc(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(2, 2, 2, 2)); }
+            static VectorType dddd(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(3, 3, 3, 3)); }
+            static VectorType dacb(VectorType x) { return _mm256_permute_ps(x, _MM_SHUFFLE(3, 0, 2, 1)); }
+
+            OP0(allone, _mm256_setallone_ps())
+            OP0(zero, _mm256_setzero_ps())
+            OP2(or_, _mm256_or_ps(a, b))
+            OP2(xor_, _mm256_xor_ps(a, b))
+            OP2(and_, _mm256_and_ps(a, b))
+            OP2(andnot_, _mm256_andnot_ps(a, b))
+            OP3(blend, _mm256_blendv_ps(a, b, c))
+        };
+
+        template<> struct VectorHelper<_M256D>
+        {
+            typedef _M256D VectorType;
+            template<typename A> static VectorType load(const double *x, A) PURE;
+            static void store(double *mem, const VectorType x, AlignedFlag);
+            static void store(double *mem, const VectorType x, UnalignedFlag);
+            static void store(double *mem, const VectorType x, StreamingAndAlignedFlag);
+            static void store(double *mem, const VectorType x, StreamingAndUnalignedFlag);
+            static void store(double *mem, const VectorType x, const VectorType m, AlignedFlag);
+            static void store(double *mem, const VectorType x, const VectorType m, UnalignedFlag);
+            static void store(double *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag);
+            static void store(double *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag);
+
+            static VectorType cdab(VectorType x) { return _mm256_permute_pd(x, 5); }
+            static VectorType badc(VectorType x) { return _mm256_permute2f128_pd(x, x, 1); }
+            // aaaa bbbb cccc dddd specialized in vector.tcc
+            static VectorType dacb(VectorType x) {
+                const __m128d cb = avx_cast<__m128d>(_mm_alignr_epi8(avx_cast<__m128i>(lo128(x)),
+                            avx_cast<__m128i>(hi128(x)), sizeof(double))); // XXX: lo and hi swapped?
+                const __m128d da = _mm_blend_pd(lo128(x), hi128(x), 0 + 2); // XXX: lo and hi swapped?
+                return concat(cb, da);
+            }
+
+            OP0(allone, _mm256_setallone_pd())
+            OP0(zero, _mm256_setzero_pd())
+            OP2(or_, _mm256_or_pd(a, b))
+            OP2(xor_, _mm256_xor_pd(a, b))
+            OP2(and_, _mm256_and_pd(a, b))
+            OP2(andnot_, _mm256_andnot_pd(a, b))
+            OP3(blend, _mm256_blendv_pd(a, b, c))
+        };
+
+        template<> struct VectorHelper<_M256I>
+        {
+            typedef _M256I VectorType;
+            template<typename T> static VectorType load(const T *x, AlignedFlag) PURE;
+            template<typename T> static VectorType load(const T *x, UnalignedFlag) PURE;
+            template<typename T> static VectorType load(const T *x, StreamingAndAlignedFlag) PURE;
+            template<typename T> static VectorType load(const T *x, StreamingAndUnalignedFlag) PURE;
+            template<typename T> static void store(T *mem, const VectorType x, AlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, UnalignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, StreamingAndAlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, StreamingAndUnalignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, AlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, UnalignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag);
+
+            static VectorType cdab(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(2, 3, 0, 1))); }
+            static VectorType badc(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(1, 0, 3, 2))); }
+            static VectorType aaaa(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(0, 0, 0, 0))); }
+            static VectorType bbbb(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(1, 1, 1, 1))); }
+            static VectorType cccc(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(2, 2, 2, 2))); }
+            static VectorType dddd(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(3, 3, 3, 3))); }
+            static VectorType dacb(VectorType x) { return avx_cast<VectorType>(_mm256_permute_ps(avx_cast<__m256>(x), _MM_SHUFFLE(3, 0, 2, 1))); }
+
+            OP0(allone, _mm256_setallone_si256())
+            OP0(zero, _mm256_setzero_si256())
+            OP2(or_, _mm256_or_si256(a, b))
+            OP2(xor_, _mm256_xor_si256(a, b))
+            OP2(and_, _mm256_and_si256(a, b))
+            OP2(andnot_, _mm256_andnot_si256(a, b))
+            OP3(blend, _mm256_blendv_epi8(a, b, c))
+        };
+
+        template<> struct VectorHelper<__m128i>
+        {
+            typedef __m128i VectorType;
+            template<typename T> static VectorType load(const T *x, AlignedFlag) PURE;
+            template<typename T> static VectorType load(const T *x, UnalignedFlag) PURE;
+            template<typename T> static VectorType load(const T *x, StreamingAndAlignedFlag) PURE;
+            template<typename T> static VectorType load(const T *x, StreamingAndUnalignedFlag) PURE;
+            template<typename T> static void store(T *mem, const VectorType x, AlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, UnalignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, StreamingAndAlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, StreamingAndUnalignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, AlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, UnalignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag);
+            template<typename T> static void store(T *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag);
+
+            static VectorType cdab(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); }
+            static VectorType badc(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(1, 0, 3, 2)), _MM_SHUFFLE(1, 0, 3, 2)); }
+            static VectorType aaaa(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(0, 0, 0, 0)), _MM_SHUFFLE(0, 0, 0, 0)); }
+            static VectorType bbbb(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(1, 1, 1, 1)), _MM_SHUFFLE(1, 1, 1, 1)); }
+            static VectorType cccc(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(2, 2, 2, 2)); }
+            static VectorType dddd(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); }
+            static VectorType dacb(VectorType x) { return _mm_shufflehi_epi16(_mm_shufflelo_epi16(x, _MM_SHUFFLE(3, 0, 2, 1)), _MM_SHUFFLE(3, 0, 2, 1)); }
+
+            OP0(allone, _mm_setallone_si128())
+            OP0(zero, _mm_setzero_si128())
+            OP2(or_, _mm_or_si128(a, b))
+            OP2(xor_, _mm_xor_si128(a, b))
+            OP2(and_, _mm_and_si128(a, b))
+            OP2(andnot_, _mm_andnot_si128(a, b))
+            OP3(blend, _mm_blendv_epi8(a, b, c))
+        };
+#undef OP1
+#undef OP2
+#undef OP3
+
+#define OP1(op) \
+        static inline VectorType INTRINSIC CONST op(const VectorType &a) { return CAT(_mm256_##op##_, SUFFIX)(a); }
+#define OP(op) \
+        static inline VectorType INTRINSIC CONST op(const VectorType &a, const VectorType &b) { return CAT(_mm256_##op##_ , SUFFIX)(a, b); }
+#define OP_(op) \
+        static inline VectorType INTRINSIC CONST op(const VectorType &a, const VectorType &b) { return CAT(_mm256_##op    , SUFFIX)(a, b); }
+#define OPx(op, op2) \
+        static inline VectorType INTRINSIC CONST op(const VectorType &a, const VectorType &b) { return CAT(_mm256_##op2##_, SUFFIX)(a, b); }
+#define OPcmp(op) \
+        static inline VectorType INTRINSIC CONST cmp##op(const VectorType &a, const VectorType &b) { return CAT(_mm256_cmp##op##_, SUFFIX)(a, b); }
+#define OP_CAST_(op) \
+        static inline VectorType INTRINSIC CONST op(const VectorType &a, const VectorType &b) { return CAT(_mm256_castps_, SUFFIX)( \
+            _mm256_##op##ps(CAT(CAT(_mm256_cast, SUFFIX), _ps)(a), \
+              CAT(CAT(_mm256_cast, SUFFIX), _ps)(b))); \
+        }
+#define MINMAX \
+        static inline VectorType INTRINSIC CONST min(VectorType a, VectorType b) { return CAT(_mm256_min_, SUFFIX)(a, b); } \
+        static inline VectorType INTRINSIC CONST max(VectorType a, VectorType b) { return CAT(_mm256_max_, SUFFIX)(a, b); }
+
+        template<> struct VectorHelper<double> {
+            typedef _M256D VectorType;
+            typedef double EntryType;
+            typedef double ConcatType;
+#define SUFFIX pd
+
+            static inline VectorType notMaskedToZero(VectorType a, _M256 mask) { return CAT(_mm256_and_, SUFFIX)(_mm256_castps_pd(mask), a); }
+            static inline VectorType set(const double a) { return CAT(_mm256_set1_, SUFFIX)(a); }
+            static inline VectorType set(const double a, const double b, const double c, const double d) {
+                return CAT(_mm256_set_, SUFFIX)(a, b, c, d);
+            }
+            static inline VectorType zero() { return CAT(_mm256_setzero_, SUFFIX)(); }
+            static inline VectorType one()  { return CAT(_mm256_setone_, SUFFIX)(); }// set(1.); }
+
+            static inline void multiplyAndAdd(VectorType &v1, VectorType v2, VectorType v3) { v1 = add(mul(v1, v2), v3); }
+            static inline VectorType mul(VectorType a, VectorType b, _M256 _mask) {
+                _M256D mask = _mm256_castps_pd(_mask);
+                return _mm256_or_pd(
+                    _mm256_and_pd(mask, _mm256_mul_pd(a, b)),
+                    _mm256_andnot_pd(mask, a)
+                    );
+            }
+            static inline VectorType div(VectorType a, VectorType b, _M256 _mask) {
+                _M256D mask = _mm256_castps_pd(_mask);
+                return _mm256_or_pd(
+                    _mm256_and_pd(mask, _mm256_div_pd(a, b)),
+                    _mm256_andnot_pd(mask, a)
+                    );
+            }
+
+            OP(add) OP(sub) OP(mul)
+            OPcmp(eq) OPcmp(neq)
+            OPcmp(lt) OPcmp(nlt)
+            OPcmp(le) OPcmp(nle)
+
+            OP1(sqrt)
+            static inline VectorType rsqrt(VectorType x) {
+                return _mm256_div_pd(one(), sqrt(x));
+            }
+            static inline VectorType reciprocal(VectorType x) {
+                return _mm256_div_pd(one(), x);
+            }
+            static inline VectorType isNaN(VectorType x) {
+                return _mm256_cmpunord_pd(x, x);
+            }
+            static inline VectorType isFinite(VectorType x) {
+                return _mm256_cmpord_pd(x, _mm256_mul_pd(zero(), x));
+            }
+            static inline VectorType abs(const VectorType a) {
+                return CAT(_mm256_and_, SUFFIX)(a, _mm256_setabsmask_pd());
+            }
+
+            MINMAX
+            static inline EntryType min(VectorType a) {
+                __m128d b = _mm_min_pd(avx_cast<__m128d>(a), _mm256_extractf128_pd(a, 1));
+                b = _mm_min_sd(b, _mm_unpackhi_pd(b, b));
+                return _mm_cvtsd_f64(b);
+            }
+            static inline EntryType max(VectorType a) {
+                __m128d b = _mm_max_pd(avx_cast<__m128d>(a), _mm256_extractf128_pd(a, 1));
+                b = _mm_max_sd(b, _mm_unpackhi_pd(b, b));
+                return _mm_cvtsd_f64(b);
+            }
+            static inline EntryType mul(VectorType a) {
+                __m128d b = _mm_mul_pd(avx_cast<__m128d>(a), _mm256_extractf128_pd(a, 1));
+                b = _mm_mul_sd(b, _mm_shuffle_pd(b, b, _MM_SHUFFLE2(0, 1)));
+                return _mm_cvtsd_f64(b);
+            }
+            static inline EntryType add(VectorType a) {
+                __m128d b = _mm_add_pd(avx_cast<__m128d>(a), _mm256_extractf128_pd(a, 1));
+                b = _mm_hadd_pd(b, b); // or: b = _mm_add_sd(b, _mm256_shuffle_pd(b, b, _MM_SHUFFLE2(0, 1)));
+                return _mm_cvtsd_f64(b);
+            }
+#undef SUFFIX
+            static inline VectorType round(VectorType a) {
+                return _mm256_round_pd(a, _MM_FROUND_NINT);
+            }
+        };
+
+        template<> struct VectorHelper<float> {
+            typedef float EntryType;
+            typedef _M256 VectorType;
+            typedef double ConcatType;
+#define SUFFIX ps
+
+            static inline VectorType notMaskedToZero(VectorType a, _M256 mask) { return CAT(_mm256_and_, SUFFIX)(mask, a); }
+            static inline VectorType set(const float a) { return CAT(_mm256_set1_, SUFFIX)(a); }
+            static inline VectorType set(const float a, const float b, const float c, const float d,
+                    const float e, const float f, const float g, const float h) {
+                return CAT(_mm256_set_, SUFFIX)(a, b, c, d, e, f, g, h); }
+            static inline VectorType zero() { return CAT(_mm256_setzero_, SUFFIX)(); }
+            static inline VectorType one()  { return CAT(_mm256_setone_, SUFFIX)(); }// set(1.f); }
+            static inline _M256 concat(_M256D a, _M256D b) { return _mm256_insertf128_ps(avx_cast<_M256>(_mm256_cvtpd_ps(a)), _mm256_cvtpd_ps(b), 1); }
+
+            static inline void multiplyAndAdd(VectorType &v1, VectorType v2, VectorType v3) { v1 = add(mul(v1, v2), v3); }
+            static inline VectorType mul(VectorType a, VectorType b, _M256 mask) {
+                return _mm256_or_ps(
+                    _mm256_and_ps(mask, _mm256_mul_ps(a, b)),
+                    _mm256_andnot_ps(mask, a)
+                    );
+            }
+            static inline VectorType div(VectorType a, VectorType b, _M256 mask) {
+                return _mm256_or_ps(
+                    _mm256_and_ps(mask, _mm256_div_ps(a, b)),
+                    _mm256_andnot_ps(mask, a)
+                    );
+            }
+
+            OP(add) OP(sub) OP(mul)
+            OPcmp(eq) OPcmp(neq)
+            OPcmp(lt) OPcmp(nlt)
+            OPcmp(le) OPcmp(nle)
+
+            OP1(sqrt) OP1(rsqrt)
+            static inline VectorType isNaN(VectorType x) {
+                return _mm256_cmpunord_ps(x, x);
+            }
+            static inline VectorType isFinite(VectorType x) {
+                return _mm256_cmpord_ps(x, _mm256_mul_ps(zero(), x));
+            }
+            static inline VectorType reciprocal(VectorType x) {
+                return _mm256_rcp_ps(x);
+            }
+            static inline VectorType abs(const VectorType a) {
+                return CAT(_mm256_and_, SUFFIX)(a, _mm256_setabsmask_ps());
+            }
+
+            MINMAX
+            static inline EntryType min(VectorType a) {
+                __m128 b = _mm_min_ps(avx_cast<__m128>(a), _mm256_extractf128_ps(a, 1));
+                b = _mm_min_ps(b, _mm_movehl_ps(b, b));   // b = min(a0, a2), min(a1, a3), min(a2, a2), min(a3, a3)
+                b = _mm_min_ss(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); // b = min(a0, a1), a1, a2, a3
+                return _mm_cvtss_f32(b);
+            }
+            static inline EntryType max(VectorType a) {
+                __m128 b = _mm_max_ps(avx_cast<__m128>(a), _mm256_extractf128_ps(a, 1));
+                b = _mm_max_ps(b, _mm_movehl_ps(b, b));   // b = max(a0, a2), max(a1, a3), max(a2, a2), max(a3, a3)
+                b = _mm_max_ss(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); // b = max(a0, a1), a1, a2, a3
+                return _mm_cvtss_f32(b);
+            }
+            static inline EntryType mul(VectorType a) {
+                __m128 b = _mm_mul_ps(avx_cast<__m128>(a), _mm256_extractf128_ps(a, 1));
+                b = _mm_mul_ps(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 1, 2, 3)));
+                b = _mm_mul_ss(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 2, 0, 1)));
+                return _mm_cvtss_f32(b);
+            }
+            static inline EntryType add(VectorType a) {
+                __m128 b = _mm_add_ps(avx_cast<__m128>(a), _mm256_extractf128_ps(a, 1));
+                b = _mm_add_ps(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 1, 2, 3)));
+                b = _mm_add_ss(b, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 2, 0, 1)));
+                return _mm_cvtss_f32(b);
+            }
+#undef SUFFIX
+            static inline VectorType round(VectorType a) {
+                return _mm256_round_ps(a, _MM_FROUND_NINT);
+            }
+        };
+
+        template<> struct VectorHelper<sfloat> : public VectorHelper<float> {};
+
+        template<> struct VectorHelper<int> {
+            typedef int EntryType;
+            typedef _M256I VectorType;
+            typedef long long ConcatType;
+#define SUFFIX si256
+
+            OP_(or_) OP_(and_) OP_(xor_)
+            static inline VectorType INTRINSIC CONST zero() { return CAT(_mm256_setzero_, SUFFIX)(); }
+            static inline VectorType INTRINSIC CONST notMaskedToZero(VectorType a, _M256 mask) { return CAT(_mm256_and_, SUFFIX)(_mm256_castps_si256(mask), a); }
+#undef SUFFIX
+#define SUFFIX epi32
+            static inline VectorType INTRINSIC CONST one() { return CAT(_mm256_setone_, SUFFIX)(); }
+
+            static inline VectorType INTRINSIC CONST set(const int a) { return CAT(_mm256_set1_, SUFFIX)(a); }
+            static inline VectorType INTRINSIC CONST set(const int a, const int b, const int c, const int d,
+                    const int e, const int f, const int g, const int h) {
+                return CAT(_mm256_set_, SUFFIX)(a, b, c, d, e, f, g, h); }
+
+            static inline void INTRINSIC CONST multiplyAndAdd(VectorType &v1, VectorType v2, VectorType v3) { v1 = add(mul(v1, v2), v3); }
+
+            static inline VectorType shiftLeft(VectorType a, int shift) {
+                return CAT(_mm256_slli_, SUFFIX)(a, shift);
+            }
+            static inline VectorType shiftRight(VectorType a, int shift) {
+                return CAT(_mm256_srai_, SUFFIX)(a, shift);
+            }
+            OP1(abs)
+
+            MINMAX
+            static inline EntryType INTRINSIC CONST min(VectorType a) {
+                __m128i b = _mm_min_epi32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_min_epi32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_min_epi32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2))); // using lo_epi16 for speed here
+                return _mm_cvtsi128_si32(b);
+            }
+            static inline EntryType INTRINSIC CONST max(VectorType a) {
+                __m128i b = _mm_max_epi32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_max_epi32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_max_epi32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2))); // using lo_epi16 for speed here
+                return _mm_cvtsi128_si32(b);
+            }
+            static inline EntryType INTRINSIC CONST add(VectorType a) {
+                __m128i b = _mm_add_epi32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_add_epi32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_add_epi32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                return _mm_cvtsi128_si32(b);
+            }
+            static inline EntryType INTRINSIC CONST mul(VectorType a) {
+                __m128i b = _mm_mullo_epi32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_mullo_epi32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_mullo_epi32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                return _mm_cvtsi128_si32(b);
+            }
+
+            static inline VectorType INTRINSIC CONST mul(VectorType a, VectorType b) { return _mm256_mullo_epi32(a, b); }
+
+            OP(add) OP(sub)
+            OPcmp(eq)
+            OPcmp(lt)
+            OPcmp(gt)
+            static inline VectorType INTRINSIC CONST cmpneq(const VectorType &a, const VectorType &b) { _M256I x = cmpeq(a, b); return _mm256_andnot_si256(x, _mm256_setallone_si256()); }
+            static inline VectorType INTRINSIC CONST cmpnlt(const VectorType &a, const VectorType &b) { _M256I x = cmplt(a, b); return _mm256_andnot_si256(x, _mm256_setallone_si256()); }
+            static inline VectorType INTRINSIC CONST cmple (const VectorType &a, const VectorType &b) { _M256I x = cmpgt(a, b); return _mm256_andnot_si256(x, _mm256_setallone_si256()); }
+            static inline VectorType INTRINSIC CONST cmpnle(const VectorType &a, const VectorType &b) { return cmpgt(a, b); }
+#undef SUFFIX
+            static inline VectorType INTRINSIC CONST round(VectorType a) { return a; }
+        };
+
+        template<> struct VectorHelper<unsigned int> {
+            typedef unsigned int EntryType;
+            typedef _M256I VectorType;
+            typedef unsigned long long ConcatType;
+#define SUFFIX si256
+            OP_CAST_(or_) OP_CAST_(and_) OP_CAST_(xor_)
+            static inline VectorType INTRINSIC CONST zero() { return CAT(_mm256_setzero_, SUFFIX)(); }
+            static inline VectorType INTRINSIC CONST notMaskedToZero(VectorType a, _M256 mask) { return CAT(_mm256_and_, SUFFIX)(_mm256_castps_si256(mask), a); }
+
+#undef SUFFIX
+#define SUFFIX epu32
+            static inline VectorType INTRINSIC CONST one() { return CAT(_mm256_setone_, SUFFIX)(); }
+
+            MINMAX
+            static inline EntryType INTRINSIC CONST min(VectorType a) {
+                __m128i b = _mm_min_epu32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_min_epu32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_min_epu32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2))); // using lo_epi16 for speed here
+                return _mm_cvtsi128_si32(b);
+            }
+            static inline EntryType INTRINSIC CONST max(VectorType a) {
+                __m128i b = _mm_max_epu32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_max_epu32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_max_epu32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2))); // using lo_epi16 for speed here
+                return _mm_cvtsi128_si32(b);
+            }
+            static inline EntryType INTRINSIC CONST add(VectorType a) {
+                __m128i b = _mm_add_epi32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_add_epi32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_add_epi32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                return _mm_cvtsi128_si32(b);
+            }
+            static inline EntryType INTRINSIC CONST mul(VectorType a) {
+                __m128i b = _mm_mullo_epi32(avx_cast<__m128i>(a), _mm256_extractf128_si256(a, 1));
+                b = _mm_mullo_epi32(b, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                b = _mm_mullo_epi32(b, _mm_shufflelo_epi16(b, _MM_SHUFFLE(1, 0, 3, 2)));
+                return _mm_cvtsi128_si32(b);
+            }
+
+            static inline VectorType INTRINSIC CONST mul(VectorType a, VectorType b) { return _mm256_mullo_epi32(a, b); }
+
+#undef SUFFIX
+#define SUFFIX epi32
+            static inline VectorType shiftLeft(VectorType a, int shift) {
+                return CAT(_mm256_slli_, SUFFIX)(a, shift);
+            }
+            static inline VectorType shiftRight(VectorType a, int shift) {
+                return CAT(_mm256_srli_, SUFFIX)(a, shift);
+            }
+            static inline VectorType INTRINSIC CONST set(const unsigned int a) { return CAT(_mm256_set1_, SUFFIX)(a); }
+            static inline VectorType INTRINSIC CONST set(const unsigned int a, const unsigned int b, const unsigned int c, const unsigned int d,
+                    const unsigned int e, const unsigned int f, const unsigned int g, const unsigned int h) {
+                return CAT(_mm256_set_, SUFFIX)(a, b, c, d, e, f, g, h); }
+
+            OP(add) OP(sub)
+            OPcmp(eq)
+            static inline VectorType INTRINSIC CONST cmpneq(const VectorType &a, const VectorType &b) { return _mm256_andnot_si256(cmpeq(a, b), _mm256_setallone_si256()); }
+
+#ifndef USE_INCORRECT_UNSIGNED_COMPARE
+            static inline VectorType INTRINSIC CONST cmplt(const VectorType &a, const VectorType &b) {
+                return _mm256_cmplt_epu32(a, b);
+            }
+            static inline VectorType INTRINSIC CONST cmpgt(const VectorType &a, const VectorType &b) {
+                return _mm256_cmpgt_epu32(a, b);
+            }
+#else
+            OPcmp(lt)
+            OPcmp(gt)
+#endif
+            static inline VectorType INTRINSIC CONST cmpnlt(const VectorType &a, const VectorType &b) { return _mm256_andnot_si256(cmplt(a, b), _mm256_setallone_si256()); }
+            static inline VectorType INTRINSIC CONST cmple (const VectorType &a, const VectorType &b) { return _mm256_andnot_si256(cmpgt(a, b), _mm256_setallone_si256()); }
+            static inline VectorType INTRINSIC CONST cmpnle(const VectorType &a, const VectorType &b) { return cmpgt(a, b); }
+
+#undef SUFFIX
+            static inline VectorType INTRINSIC CONST round(VectorType a) { return a; }
+        };
+
+        template<> struct VectorHelper<signed short> {
+            typedef VectorTypeHelper<signed short>::Type VectorType;
+            typedef signed short EntryType;
+            typedef int ConcatType;
+
+            static inline VectorType INTRINSIC CONST or_(VectorType a, VectorType b) { return _mm_or_si128(a, b); }
+            static inline VectorType INTRINSIC CONST and_(VectorType a, VectorType b) { return _mm_and_si128(a, b); }
+            static inline VectorType INTRINSIC CONST xor_(VectorType a, VectorType b) { return _mm_xor_si128(a, b); }
+            static inline VectorType INTRINSIC CONST zero() { return _mm_setzero_si128(); }
+            static inline VectorType INTRINSIC CONST notMaskedToZero(VectorType a, __m128 mask) { return _mm_and_si128(_mm_castps_si128(mask), a); }
+
+#define SUFFIX epi16
+            static inline VectorType INTRINSIC CONST one() { return CAT(_mm_setone_, SUFFIX)(); }
+
+            static inline VectorType shiftLeft(VectorType a, int shift) {
+                return CAT(_mm_slli_, SUFFIX)(a, shift);
+            }
+            static inline VectorType shiftRight(VectorType a, int shift) {
+                return CAT(_mm_srai_, SUFFIX)(a, shift);
+            }
+            static inline VectorType INTRINSIC CONST set(const EntryType a) { return CAT(_mm_set1_, SUFFIX)(a); }
+            static inline VectorType INTRINSIC CONST set(const EntryType a, const EntryType b, const EntryType c, const EntryType d,
+                    const EntryType e, const EntryType f, const EntryType g, const EntryType h) {
+                return CAT(_mm_set_, SUFFIX)(a, b, c, d, e, f, g, h);
+            }
+
+            static inline void INTRINSIC CONST multiplyAndAdd(VectorType &v1, VectorType v2, VectorType v3) {
+                v1 = add(mul(v1, v2), v3); }
+
+            static inline VectorType INTRINSIC CONST abs(VectorType a) { return _mm_abs_epi16(a); }
+            static inline VectorType INTRINSIC CONST mul(VectorType a, VectorType b) { return _mm_mullo_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST min(VectorType a, VectorType b) { return _mm_min_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST max(VectorType a, VectorType b) { return _mm_max_epi16(a, b); }
+
+            static inline EntryType INTRINSIC CONST min(VectorType a) {
+                // reminder: _MM_SHUFFLE(3, 2, 1, 0) means "no change"
+                a = min(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = min(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = min(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline EntryType INTRINSIC CONST max(VectorType a) {
+                // reminder: _MM_SHUFFLE(3, 2, 1, 0) means "no change"
+                a = max(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = max(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = max(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline EntryType INTRINSIC CONST mul(VectorType a) {
+                a = mul(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = mul(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = mul(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline EntryType INTRINSIC CONST add(VectorType a) {
+                a = add(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = add(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = add(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+
+            static inline VectorType INTRINSIC CONST add(VectorType a, VectorType b) { return _mm_add_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST sub(VectorType a, VectorType b) { return _mm_sub_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST cmpeq(VectorType a, VectorType b) { return _mm_cmpeq_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST cmplt(VectorType a, VectorType b) { return _mm_cmplt_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST cmpgt(VectorType a, VectorType b) { return _mm_cmpgt_epi16(a, b); }
+            static inline VectorType cmpneq(const VectorType &a, const VectorType &b) { __m128i x = cmpeq(a, b); return _mm_andnot_si128(x, _mm_setallone_si128()); }
+            static inline VectorType cmpnlt(const VectorType &a, const VectorType &b) { __m128i x = cmplt(a, b); return _mm_andnot_si128(x, _mm_setallone_si128()); }
+            static inline VectorType cmple (const VectorType &a, const VectorType &b) { __m128i x = cmpgt(a, b); return _mm_andnot_si128(x, _mm_setallone_si128()); }
+            static inline VectorType cmpnle(const VectorType &a, const VectorType &b) { return cmpgt(a, b); }
+#undef SUFFIX
+            static inline VectorType round(VectorType a) { return a; }
+        };
+
+        template<> struct VectorHelper<unsigned short> {
+            typedef VectorTypeHelper<unsigned short>::Type VectorType;
+            typedef unsigned short EntryType;
+            typedef unsigned int ConcatType;
+
+            static inline VectorType INTRINSIC CONST or_(VectorType a, VectorType b) { return _mm_or_si128(a, b); }
+            static inline VectorType INTRINSIC CONST and_(VectorType a, VectorType b) { return _mm_and_si128(a, b); }
+            static inline VectorType INTRINSIC CONST xor_(VectorType a, VectorType b) { return _mm_xor_si128(a, b); }
+            static inline VectorType INTRINSIC CONST zero() { return _mm_setzero_si128(); }
+            static inline VectorType INTRINSIC CONST notMaskedToZero(VectorType a, __m128 mask) { return _mm_and_si128(_mm_castps_si128(mask), a); }
+            static inline VectorType INTRINSIC CONST one() { return _mm_setone_epu16(); }
+
+            static inline VectorType INTRINSIC CONST mul(VectorType a, VectorType b) { return _mm_mullo_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST min(VectorType a, VectorType b) { return _mm_min_epu16(a, b); }
+            static inline VectorType INTRINSIC CONST max(VectorType a, VectorType b) { return _mm_max_epu16(a, b); }
+
+#define SUFFIX epi16
+            static inline VectorType shiftLeft(VectorType a, int shift) {
+                return CAT(_mm_slli_, SUFFIX)(a, shift);
+            }
+            static inline VectorType shiftRight(VectorType a, int shift) {
+                return CAT(_mm_srli_, SUFFIX)(a, shift);
+            }
+            static inline EntryType INTRINSIC CONST min(VectorType a) {
+                // reminder: _MM_SHUFFLE(3, 2, 1, 0) means "no change"
+                a = min(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = min(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = min(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline EntryType INTRINSIC CONST max(VectorType a) {
+                // reminder: _MM_SHUFFLE(3, 2, 1, 0) means "no change"
+                a = max(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = max(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = max(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline EntryType INTRINSIC CONST mul(VectorType a) {
+                // reminder: _MM_SHUFFLE(3, 2, 1, 0) means "no change"
+                a = mul(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = mul(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = mul(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline EntryType INTRINSIC CONST add(VectorType a) {
+                // reminder: _MM_SHUFFLE(3, 2, 1, 0) means "no change"
+                a = add(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = add(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 0, 3, 2)));
+                a = add(a, _mm_shufflelo_epi16(a, _MM_SHUFFLE(1, 1, 1, 1)));
+                return _mm_cvtsi128_si32(a); // & 0xffff is implicit
+            }
+            static inline VectorType INTRINSIC CONST set(const EntryType a) { return CAT(_mm_set1_, SUFFIX)(a); }
+            static inline VectorType INTRINSIC CONST set(const EntryType a, const EntryType b, const EntryType c,
+                    const EntryType d, const EntryType e, const EntryType f,
+                    const EntryType g, const EntryType h) {
+                return CAT(_mm_set_, SUFFIX)(a, b, c, d, e, f, g, h);
+            }
+
+            static inline VectorType INTRINSIC CONST add(VectorType a, VectorType b) { return _mm_add_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST sub(VectorType a, VectorType b) { return _mm_sub_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST cmpeq(VectorType a, VectorType b) { return _mm_cmpeq_epi16(a, b); }
+            static inline VectorType cmpneq(const VectorType &a, const VectorType &b) { return _mm_andnot_si128(cmpeq(a, b), _mm_setallone_si128()); }
+
+#ifndef USE_INCORRECT_UNSIGNED_COMPARE
+            static inline VectorType INTRINSIC CONST cmplt(VectorType a, VectorType b) { return _mm_cmplt_epu16(a, b); }
+            static inline VectorType INTRINSIC CONST cmpgt(VectorType a, VectorType b) { return _mm_cmpgt_epu16(a, b); }
+#else
+            static inline VectorType INTRINSIC CONST cmplt(VectorType a, VectorType b) { return _mm_cmplt_epi16(a, b); }
+            static inline VectorType INTRINSIC CONST cmpgt(VectorType a, VectorType b) { return _mm_cmpgt_epi16(a, b); }
+#endif
+            static inline VectorType cmpnlt(const VectorType &a, const VectorType &b) { return _mm_andnot_si128(cmplt(a, b), _mm_setallone_si128()); }
+            static inline VectorType cmple (const VectorType &a, const VectorType &b) { return _mm_andnot_si128(cmpgt(a, b), _mm_setallone_si128()); }
+            static inline VectorType cmpnle(const VectorType &a, const VectorType &b) { return cmpgt(a, b); }
+#undef SUFFIX
+            static inline VectorType round(VectorType a) { return a; }
+        };
+#undef OP1
+#undef OP
+#undef OP_
+#undef OPx
+#undef OPcmp
+
+template<> struct VectorHelper<char>
+{
+    typedef VectorTypeHelper<char>::Type VectorType;
+    typedef char EntryType;
+    typedef short ConcatType;
+};
+
+template<> struct VectorHelper<unsigned char>
+{
+    typedef VectorTypeHelper<unsigned char>::Type VectorType;
+    typedef unsigned char EntryType;
+    typedef unsigned short ConcatType;
+};
+
+} // namespace AVX
+} // namespace Vc
+
+#include "vectorhelper.tcc"
+
+#endif // AVX_VECTORHELPER_H
diff --git a/Vc/include/Vc/avx/vectorhelper.tcc b/Vc/include/Vc/avx/vectorhelper.tcc
new file mode 100644 (file)
index 0000000..e1da822
--- /dev/null
@@ -0,0 +1,268 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "casts.h"
+#include <cstdlib>
+
+namespace Vc
+{
+namespace AVX
+{
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// float_v
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// loads
+template<> inline __m256 VectorHelper<__m256>::load(const float *m, AlignedFlag)
+{
+    return _mm256_load_ps(m);
+}
+template<> inline __m256 VectorHelper<__m256>::load(const float *m, UnalignedFlag)
+{
+    return _mm256_loadu_ps(m);
+}
+template<> inline __m256 VectorHelper<__m256>::load(const float *m, StreamingAndAlignedFlag)
+{
+    return avx_cast<__m256>(concat(_mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<float *>(m))),
+                _mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<float *>(&m[4])))));
+}
+template<> inline __m256
+    VC_WARN("AVX does not support streaming unaligned loads. Will use non-streaming unaligned load instead.")
+VectorHelper<__m256>::load(const float *m, StreamingAndUnalignedFlag)
+{
+    return _mm256_loadu_ps(m);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// stores
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, AlignedFlag)
+{
+    _mm256_store_ps(mem, x);
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, UnalignedFlag)
+{
+    _mm256_storeu_ps(mem, x);
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, StreamingAndAlignedFlag)
+{
+    _mm256_stream_ps(mem, x);
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), _mm_setallone_si128(), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(_mm256_extractf128_si256(avx_cast<__m256i>(x), 1), _mm_setallone_si128(), reinterpret_cast<char *>(mem + 4));
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, const VectorType m, AlignedFlag)
+{
+    _mm256_maskstore(mem, m, x);
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, const VectorType m, UnalignedFlag)
+{
+    _mm256_maskstore(mem, m, x);
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), avx_cast<__m128i>(m), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(_mm256_extractf128_si256(avx_cast<__m256i>(x), 1), _mm256_extractf128_si256(avx_cast<__m256i>(m), 1), reinterpret_cast<char *>(mem + 4));
+}
+inline void VectorHelper<__m256>::store(float *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), avx_cast<__m128i>(m), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(_mm256_extractf128_si256(avx_cast<__m256i>(x), 1), _mm256_extractf128_si256(avx_cast<__m256i>(m), 1), reinterpret_cast<char *>(mem + 4));
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// double_v
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// loads
+template<> inline __m256d VectorHelper<__m256d>::load(const double *m, AlignedFlag)
+{
+    return _mm256_load_pd(m);
+}
+template<> inline __m256d VectorHelper<__m256d>::load(const double *m, UnalignedFlag)
+{
+    return _mm256_loadu_pd(m);
+}
+template<> inline __m256d VectorHelper<__m256d>::load(const double *m, StreamingAndAlignedFlag)
+{
+    return avx_cast<__m256d>(concat(
+                _mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<double *>(m))),
+                _mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<double *>(&m[2])))));
+}
+template<> inline __m256d
+    VC_WARN("AVX does not support streaming unaligned loads. Will use non-streaming unaligned load instead.")
+VectorHelper<__m256d>::load(const double *m, StreamingAndUnalignedFlag)
+{
+    return _mm256_loadu_pd(m);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// stores
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, AlignedFlag)
+{
+    _mm256_store_pd(mem, x);
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, UnalignedFlag)
+{
+    _mm256_storeu_pd(mem, x);
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, StreamingAndAlignedFlag)
+{
+    _mm256_stream_pd(mem, x);
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), _mm_setallone_si128(), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(avx_cast<__m128i>(_mm256_extractf128_pd(x, 1)), _mm_setallone_si128(), reinterpret_cast<char *>(mem + 2));
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, const VectorType m, AlignedFlag)
+{
+    _mm256_maskstore(mem, m, x);
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, const VectorType m, UnalignedFlag)
+{
+    _mm256_maskstore(mem, m, x);
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), avx_cast<__m128i>(m), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(avx_cast<__m128i>(_mm256_extractf128_pd(x, 1)), avx_cast<__m128i>(_mm256_extractf128_pd(m, 1)), reinterpret_cast<char *>(mem + 2));
+}
+inline void VectorHelper<__m256d>::store(double *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), avx_cast<__m128i>(m), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(avx_cast<__m128i>(_mm256_extractf128_pd(x, 1)), avx_cast<__m128i>(_mm256_extractf128_pd(m, 1)), reinterpret_cast<char *>(mem + 2));
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// (u)int_v
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// loads
+template<typename T> inline __m256i VectorHelper<__m256i>::load(const T *m, AlignedFlag)
+{
+    return _mm256_load_si256(reinterpret_cast<const __m256i *>(m));
+}
+template<typename T> inline __m256i VectorHelper<__m256i>::load(const T *m, UnalignedFlag)
+{
+    return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(m));
+}
+template<typename T> inline __m256i VectorHelper<__m256i>::load(const T *m, StreamingAndAlignedFlag)
+{
+    return concat(_mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<T *>(m))),
+            _mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<T *>(&m[4]))));
+}
+template<typename T> inline __m256i
+    VC_WARN("AVX does not support streaming unaligned loads. Will use non-streaming unaligned load instead.")
+VectorHelper<__m256i>::load(const T *m, StreamingAndUnalignedFlag)
+{
+    return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(m));
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// stores
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, AlignedFlag)
+{
+    _mm256_store_si256(reinterpret_cast<VectorType *>(mem), x);
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, UnalignedFlag)
+{
+    _mm256_storeu_si256(reinterpret_cast<VectorType *>(mem), x);
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, StreamingAndAlignedFlag)
+{
+    _mm256_stream_si256(reinterpret_cast<VectorType *>(mem), x);
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(avx_cast<__m128i>(x), _mm_setallone_si128(), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(_mm256_extractf128_si256(x, 1), _mm_setallone_si128(), reinterpret_cast<char *>(mem + 4));
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, const VectorType m, AlignedFlag)
+{
+    _mm256_maskstore(mem, m, x);
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, const VectorType m, UnalignedFlag)
+{
+    _mm256_maskstore(mem, m, x);
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag)
+{
+    _mm_maskmoveu_si128(lo128(x), lo128(m), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(hi128(x), hi128(m), reinterpret_cast<char *>(mem + 4));
+}
+template<typename T> inline void VectorHelper<__m256i>::store(T *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(lo128(x), lo128(m), reinterpret_cast<char *>(mem));
+    _mm_maskmoveu_si128(hi128(x), hi128(m), reinterpret_cast<char *>(mem + 4));
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// (u)short_v
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// loads
+template<typename T> inline __m128i VectorHelper<__m128i>::load(const T *m, AlignedFlag)
+{
+    return _mm_load_si128(reinterpret_cast<const __m128i *>(m));
+}
+template<typename T> inline __m128i VectorHelper<__m128i>::load(const T *m, UnalignedFlag)
+{
+    return _mm_loadu_si128(reinterpret_cast<const __m128i *>(m));
+}
+template<typename T> inline __m128i VectorHelper<__m128i>::load(const T *m, StreamingAndAlignedFlag)
+{
+    return _mm_stream_load_si128(reinterpret_cast<__m128i *>(const_cast<T *>(m)));
+}
+template<typename T> inline __m128i
+    VC_WARN("AVX does not support streaming unaligned loads. Will use non-streaming unaligned load instead.")
+VectorHelper<__m128i>::load(const T *m, StreamingAndUnalignedFlag)
+{
+    return _mm_loadu_si128(reinterpret_cast<const __m128i *>(m));
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//// stores
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, AlignedFlag)
+{
+    _mm_store_si128(reinterpret_cast<VectorType *>(mem), x);
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, UnalignedFlag)
+{
+    _mm_storeu_si128(reinterpret_cast<VectorType *>(mem), x);
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, StreamingAndAlignedFlag)
+{
+    _mm_stream_si128(reinterpret_cast<VectorType *>(mem), x);
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(x, _mm_setallone_si128(), reinterpret_cast<char *>(mem));
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, const VectorType m, AlignedFlag align)
+{
+    store(mem, _mm_blendv_epi8(load(mem, align), x, m), align);
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, const VectorType m, UnalignedFlag align)
+{
+    store(mem, _mm_blendv_epi8(load(mem, align), x, m), align);
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, const VectorType m, StreamingAndAlignedFlag)
+{
+    _mm_maskmoveu_si128(x, m, reinterpret_cast<char *>(mem));
+}
+template<typename T> inline void VectorHelper<__m128i>::store(T *mem, const VectorType x, const VectorType m, StreamingAndUnalignedFlag)
+{
+    _mm_maskmoveu_si128(x, m, reinterpret_cast<char *>(mem));
+}
+
+} // namespace AVX
+} // namespace Vc
diff --git a/Vc/include/Vc/avx/writemaskedvector.h b/Vc/include/Vc/avx/writemaskedvector.h
new file mode 100644 (file)
index 0000000..a213873
--- /dev/null
@@ -0,0 +1,78 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_AVX_WRITEMASKEDVECTOR_H
+#define VC_AVX_WRITEMASKEDVECTOR_H
+
+namespace Vc
+{
+namespace AVX
+{
+
+template<typename T>
+class WriteMaskedVector
+{
+    friend class Vector<T>;
+    typedef typename VectorTypeHelper<T>::Type VectorType;
+    typedef typename DetermineEntryType<T>::Type EntryType;
+    enum Constants { Size = sizeof(VectorType) / sizeof(EntryType) };
+    typedef typename Vc::AVX::Mask<Size, sizeof(VectorType)> Mask;
+    public:
+        FREE_STORE_OPERATORS_ALIGNED(32)
+        //prefix
+        Vector<T> ALWAYS_INLINE_L &operator++() ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE_L &operator--() ALWAYS_INLINE_R;
+        //postfix
+        Vector<T> ALWAYS_INLINE_L operator++(int) ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE_L operator--(int) ALWAYS_INLINE_R;
+
+        Vector<T> ALWAYS_INLINE_L &operator+=(const Vector<T> &x) ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE_L &operator-=(const Vector<T> &x) ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE_L &operator*=(const Vector<T> &x) ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE_L &operator/=(const Vector<T> &x) ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE &operator+=(EntryType x) { return operator+=(Vector<T>(x)); }
+        Vector<T> ALWAYS_INLINE &operator-=(EntryType x) { return operator-=(Vector<T>(x)); }
+        Vector<T> ALWAYS_INLINE &operator*=(EntryType x) { return operator*=(Vector<T>(x)); }
+        Vector<T> ALWAYS_INLINE &operator/=(EntryType x) { return operator/=(Vector<T>(x)); }
+
+        Vector<T> ALWAYS_INLINE_L &operator=(const Vector<T> &x) ALWAYS_INLINE_R;
+        Vector<T> ALWAYS_INLINE &operator=(EntryType x) { return operator=(Vector<T>(x)); }
+
+        template<typename F> inline void INTRINSIC call(const F &f) const {
+            return vec->call(f, mask);
+        }
+        template<typename F> inline void INTRINSIC call(F &f) const {
+            return vec->call(f, mask);
+        }
+        template<typename F> inline Vector<T> INTRINSIC apply(const F &f) const {
+            return vec->apply(f, mask);
+        }
+        template<typename F> inline Vector<T> INTRINSIC apply(F &f) const {
+            return vec->apply(f, mask);
+        }
+    private:
+        inline WriteMaskedVector(Vector<T> *v, const Mask &k) : vec(v), mask(k) {}
+        Vector<T> *const vec;
+        Mask mask;
+};
+
+} // namespace AVX
+} // namespace Vc
+#include "writemaskedvector.tcc"
+#endif // VC_AVX_WRITEMASKEDVECTOR_H
diff --git a/Vc/include/Vc/avx/writemaskedvector.tcc b/Vc/include/Vc/avx/writemaskedvector.tcc
new file mode 100644 (file)
index 0000000..aa8b774
--- /dev/null
@@ -0,0 +1,91 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+namespace Vc
+{
+namespace AVX
+{
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator++()
+{
+    vec->data() = VectorHelper<T>::add(vec->data(),
+            VectorHelper<T>::notMaskedToZero(VectorHelper<T>::one(), mask.data())
+            );
+    return *vec;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator--() {
+    vec->data() = VectorHelper<T>::sub(vec->data(),
+            VectorHelper<T>::notMaskedToZero(VectorHelper<T>::one(), mask.data())
+            );
+    return *vec;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE WriteMaskedVector<T>::operator++(int) {
+    Vector<T> ret(*vec);
+    vec->data() = VectorHelper<T>::add(vec->data(),
+            VectorHelper<T>::notMaskedToZero(VectorHelper<T>::one(), mask.data())
+            );
+    return ret;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE WriteMaskedVector<T>::operator--(int) {
+    Vector<T> ret(*vec);
+    vec->data() = VectorHelper<T>::sub(vec->data(),
+            VectorHelper<T>::notMaskedToZero(VectorHelper<T>::one(), mask.data())
+            );
+    return ret;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator+=(const Vector<T> &x) {
+    vec->data() = VectorHelper<T>::add(vec->data(), VectorHelper<T>::notMaskedToZero(x.data(), mask.data()));
+    return *vec;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator-=(const Vector<T> &x) {
+    vec->data() = VectorHelper<T>::sub(vec->data(), VectorHelper<T>::notMaskedToZero(x.data(), mask.data()));
+    return *vec;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator*=(const Vector<T> &x) {
+    vec->assign(VectorHelper<T>::mul(vec->data(), x.data()), mask);
+    return *vec;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator/=(const Vector<T> &x) {
+    vec->assign(*vec / x, mask);
+    return *vec;
+}
+
+template<typename T>
+inline Vector<T> ALWAYS_INLINE &WriteMaskedVector<T>::operator=(const Vector<T> &x) {
+    vec->assign(x, mask);
+    return *vec;
+}
+
+} // namespace AVX
+} // namespace Vc
diff --git a/Vc/include/Vc/common/aliasingentryhelper.h b/Vc/include/Vc/common/aliasingentryhelper.h
new file mode 100644 (file)
index 0000000..d28855b
--- /dev/null
@@ -0,0 +1,114 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_COMMON_ALIASINGENTRYHELPER_H
+#define VC_COMMON_ALIASINGENTRYHELPER_H
+
+#include "macros.h"
+
+namespace Vc
+{
+namespace Common
+{
+
+template<class StorageType> class AliasingEntryHelper
+{
+    private:
+        typedef typename StorageType::EntryType T;
+#ifdef VC_ICC
+        StorageType *const m_storage;
+        const int m_index;
+    public:
+        AliasingEntryHelper(StorageType *d, int index) : m_storage(d), m_index(index) {}
+        AliasingEntryHelper(const AliasingEntryHelper &rhs) : m_storage(rhs.m_storage), m_index(rhs.m_index) {}
+        AliasingEntryHelper &operator=(const AliasingEntryHelper &rhs) {
+            m_storage->assign(m_index, rhs);
+            return *this;
+        }
+
+        AliasingEntryHelper &operator  =(T x) { m_storage->assign(m_index, x); return *this; }
+        AliasingEntryHelper &operator +=(T x) { m_storage->assign(m_index, m_storage->m(m_index) + x); return *this; }
+        AliasingEntryHelper &operator -=(T x) { m_storage->assign(m_index, m_storage->m(m_index) - x); return *this; }
+        AliasingEntryHelper &operator /=(T x) { m_storage->assign(m_index, m_storage->m(m_index) / x); return *this; }
+        AliasingEntryHelper &operator *=(T x) { m_storage->assign(m_index, m_storage->m(m_index) * x); return *this; }
+        AliasingEntryHelper &operator |=(T x) { m_storage->assign(m_index, m_storage->m(m_index) | x); return *this; }
+        AliasingEntryHelper &operator &=(T x) { m_storage->assign(m_index, m_storage->m(m_index) & x); return *this; }
+        AliasingEntryHelper &operator ^=(T x) { m_storage->assign(m_index, m_storage->m(m_index) ^ x); return *this; }
+        AliasingEntryHelper &operator %=(T x) { m_storage->assign(m_index, m_storage->m(m_index) % x); return *this; }
+        AliasingEntryHelper &operator<<=(T x) { m_storage->assign(m_index, m_storage->m(m_index)<< x); return *this; }
+        AliasingEntryHelper &operator>>=(T x) { m_storage->assign(m_index, m_storage->m(m_index)>> x); return *this; }
+#define m_data m_storage->read(m_index)
+#else
+        typedef T A MAY_ALIAS;
+        A &m_data;
+    public:
+        template<typename T2>
+        AliasingEntryHelper(T2 &d) : m_data(reinterpret_cast<A &>(d)) {}
+
+        AliasingEntryHelper(A &d) : m_data(d) {}
+        AliasingEntryHelper &operator=(const AliasingEntryHelper &rhs) {
+            m_data = rhs.m_data;
+            return *this;
+        }
+
+        AliasingEntryHelper &operator =(T x) { m_data  = x; return *this; }
+        AliasingEntryHelper &operator+=(T x) { m_data += x; return *this; }
+        AliasingEntryHelper &operator-=(T x) { m_data -= x; return *this; }
+        AliasingEntryHelper &operator/=(T x) { m_data /= x; return *this; }
+        AliasingEntryHelper &operator*=(T x) { m_data *= x; return *this; }
+        AliasingEntryHelper &operator|=(T x) { m_data |= x; return *this; }
+        AliasingEntryHelper &operator&=(T x) { m_data &= x; return *this; }
+        AliasingEntryHelper &operator^=(T x) { m_data ^= x; return *this; }
+        AliasingEntryHelper &operator%=(T x) { m_data %= x; return *this; }
+        AliasingEntryHelper &operator<<=(T x) { m_data <<= x; return *this; }
+        AliasingEntryHelper &operator>>=(T x) { m_data >>= x; return *this; }
+#endif
+
+        operator const T() const { return m_data; }
+
+        bool operator==(T x) const { return static_cast<T>(m_data) == x; }
+        bool operator!=(T x) const { return static_cast<T>(m_data) != x; }
+        bool operator<=(T x) const { return static_cast<T>(m_data) <= x; }
+        bool operator>=(T x) const { return static_cast<T>(m_data) >= x; }
+        bool operator< (T x) const { return static_cast<T>(m_data) <  x; }
+        bool operator> (T x) const { return static_cast<T>(m_data) >  x; }
+
+        T operator-() const { return -static_cast<T>(m_data); }
+        T operator~() const { return ~static_cast<T>(m_data); }
+        T operator+(T x) const { return static_cast<T>(m_data) + x; }
+        T operator-(T x) const { return static_cast<T>(m_data) - x; }
+        T operator/(T x) const { return static_cast<T>(m_data) / x; }
+        T operator*(T x) const { return static_cast<T>(m_data) * x; }
+        T operator|(T x) const { return static_cast<T>(m_data) | x; }
+        T operator&(T x) const { return static_cast<T>(m_data) & x; }
+        T operator^(T x) const { return static_cast<T>(m_data) ^ x; }
+        T operator%(T x) const { return static_cast<T>(m_data) % x; }
+        //T operator<<(T x) const { return static_cast<T>(m_data) << x; }
+        //T operator>>(T x) const { return static_cast<T>(m_data) >> x; }
+#ifdef m_data
+#undef m_data
+#endif
+};
+
+} // namespace Common
+} // namespace Vc
+
+#include "undomacros.h"
+
+#endif // VC_COMMON_ALIASINGENTRYHELPER_H
diff --git a/Vc/include/Vc/common/bitscanintrinsics.h b/Vc/include/Vc/common/bitscanintrinsics.h
new file mode 100644 (file)
index 0000000..1574c6d
--- /dev/null
@@ -0,0 +1,60 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_COMMON_BITSCANINTRINSICS_H
+#define VC_COMMON_BITSCANINTRINSICS_H
+
+#if defined(VC_GCC) || defined(VC_CLANG)
+#  if VC_GCC >= 0x40500
+     // GCC 4.5.0 introduced _bit_scan_forward / _bit_scan_reverse
+#    include <x86intrin.h>
+#  else
+     // GCC <= 4.4 and clang have x86intrin.h, but not the required functions
+#    define _bit_scan_forward(x) __builtin_ctz(x)
+static inline int _Vc_bit_scan_reverse_asm(unsigned int x) {
+    int r;
+    __asm__("bsr %1,%0" : "=r"(r) : "X"(x));
+    return r;
+}
+#    define _bit_scan_reverse(x) _Vc_bit_scan_reverse_asm(x)
+#  endif
+#elif defined(VC_ICC)
+// for all I know ICC supports the _bit_scan_* intrinsics
+#elif defined(VC_OPEN64)
+// TODO
+#elif defined(VC_MSVC)
+#include "windows_fix_intrin.h"
+#pragma intrinsic(_BitScanForward)
+#pragma intrinsic(_BitScanReverse)
+static inline __forceinline unsigned long _bit_scan_forward(unsigned long x) {
+    unsigned long index;
+    _BitScanForward(&index, x);
+    return index;
+}
+static inline __forceinline unsigned long _bit_scan_reverse(unsigned long x) {
+    unsigned long index;
+    _BitScanReverse(&index, x);
+    return index;
+}
+#else
+// just assume the compiler can do it
+#endif
+
+
+#endif // VC_COMMON_BITSCANINTRINSICS_H
diff --git a/Vc/include/Vc/common/const.h b/Vc/include/Vc/common/const.h
new file mode 100644 (file)
index 0000000..b9730c1
--- /dev/null
@@ -0,0 +1,64 @@
+/*  This file is part of the Vc library. {{{
+
+    Copyright (C) 2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+}}}*/
+
+#ifndef VC_COMMON_CONST_H
+#define VC_COMMON_CONST_H
+
+#include "macros.h"
+
+namespace Vc
+{
+    template<typename T> struct Math;
+    template<> struct Math<float>
+    {
+        static _VC_CONSTEXPR float e()         { return 2.7182818284590452353602874713526625f; }
+        static _VC_CONSTEXPR float log2e()     { return 1.4426950408889634073599246810018921f; }
+        static _VC_CONSTEXPR float log10e()    { return 0.4342944819032518276511289189166051f; }
+        static _VC_CONSTEXPR float ln2()       { return 0.6931471805599453094172321214581766f; }
+        static _VC_CONSTEXPR float ln10()      { return 2.3025850929940456840179914546843642f; }
+        static _VC_CONSTEXPR float pi()        { return 3.1415926535897932384626433832795029f; }
+        static _VC_CONSTEXPR float pi_2()      { return 1.5707963267948966192313216916397514f; }
+        static _VC_CONSTEXPR float pi_4()      { return 0.7853981633974483096156608458198757f; }
+        static _VC_CONSTEXPR float _1_pi()     { return 0.3183098861837906715377675267450287f; }
+        static _VC_CONSTEXPR float _2_pi()     { return 0.6366197723675813430755350534900574f; }
+        static _VC_CONSTEXPR float _2_sqrtpi() { return 1.1283791670955125738961589031215452f; }
+        static _VC_CONSTEXPR float sqrt2()     { return 1.4142135623730950488016887242096981f; }
+        static _VC_CONSTEXPR float sqrt1_2()   { return 0.7071067811865475244008443621048490f; }
+    };
+    template<> struct Math<double>
+    {
+        static _VC_CONSTEXPR double e()         { return 2.7182818284590452353602874713526625; }
+        static _VC_CONSTEXPR double log2e()     { return 1.4426950408889634073599246810018921; }
+        static _VC_CONSTEXPR double log10e()    { return 0.4342944819032518276511289189166051; }
+        static _VC_CONSTEXPR double ln2()       { return 0.6931471805599453094172321214581766; }
+        static _VC_CONSTEXPR double ln10()      { return 2.3025850929940456840179914546843642; }
+        static _VC_CONSTEXPR double pi()        { return 3.1415926535897932384626433832795029; }
+        static _VC_CONSTEXPR double pi_2()      { return 1.5707963267948966192313216916397514; }
+        static _VC_CONSTEXPR double pi_4()      { return 0.7853981633974483096156608458198757; }
+        static _VC_CONSTEXPR double _1_pi()     { return 0.3183098861837906715377675267450287; }
+        static _VC_CONSTEXPR double _2_pi()     { return 0.6366197723675813430755350534900574; }
+        static _VC_CONSTEXPR double _2_sqrtpi() { return 1.1283791670955125738961589031215452; }
+        static _VC_CONSTEXPR double sqrt2()     { return 1.4142135623730950488016887242096981; }
+        static _VC_CONSTEXPR double sqrt1_2()   { return 0.7071067811865475244008443621048490; }
+    };
+} // namespace Vc
+
+#include "undomacros.h"
+
+#endif // VC_COMMON_CONST_H
diff --git a/Vc/include/Vc/common/deinterleave.h b/Vc/include/Vc/common/deinterleave.h
new file mode 100644 (file)
index 0000000..772541f
--- /dev/null
@@ -0,0 +1,80 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010-2011 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_COMMON_DEINTERLEAVE_H
+#define VC_COMMON_DEINTERLEAVE_H
+
+namespace Vc
+{
+
+/**
+ * \ingroup Utilities
+ *
+ * Loads two vectors of values from an interleaved array.
+ *
+ * \param a, b The vectors to load the values from memory into.
+ * \param memory The memory location where to read the next 2 * V::Size values from
+ * \param align Either pass Vc::Aligned or Vc::Unaligned. It defaults to Vc::Aligned if nothing is
+ * specified.
+ *
+ * If you store your data as
+ * \code
+ * struct { float x, y; } m[1000];
+ * \endcode
+ * then the deinterleave function allows you to read \p Size concurrent x and y values like this:
+ * \code
+ * Vc::float_v x, y;
+ * Vc::deinterleave(&x, &y, &m[10], Vc::Unaligned);
+ * \endcode
+ * This code will load m[10], m[12], m[14], ... into \p x and m[11], m[13], m[15], ... into \p y.
+ *
+ * The deinterleave function supports the following type combinations:
+\verbatim
+  V \  M | float | double | ushort | short | uint | int
+=========|=======|========|========|=======|======|=====
+ float_v |   X   |        |    X   |   X   |      |
+---------|-------|--------|--------|-------|------|-----
+sfloat_v |   X   |        |    X   |   X   |      |
+---------|-------|--------|--------|-------|------|-----
+double_v |       |    X   |        |       |      |
+---------|-------|--------|--------|-------|------|-----
+   int_v |       |        |        |   X   |      |  X
+---------|-------|--------|--------|-------|------|-----
+  uint_v |       |        |    X   |       |   X  |
+---------|-------|--------|--------|-------|------|-----
+ short_v |       |        |        |   X   |      |
+---------|-------|--------|--------|-------|------|-----
+ushort_v |       |        |    X   |       |      |
+\endverbatim
+ */
+template<typename V, typename M, typename A> inline void deinterleave(V *a, V *b,
+        const M *memory, A align)
+{
+    Internal::Helper::deinterleave(*a, *b, memory, align);
+}
+
+// documented as default for align above
+template<typename V, typename M> inline void deinterleave(V *a, V *b,
+        const M *memory)
+{
+    Internal::Helper::deinterleave(*a, *b, memory, Aligned);
+}
+
+} // namespace Vc
+#endif // VC_COMMON_DEINTERLEAVE_H
diff --git a/Vc/include/Vc/common/exponential.h b/Vc/include/Vc/common/exponential.h
new file mode 100644 (file)
index 0000000..54ebcc2
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef COMMON_EXPONENTIAL_H
+#define COMMON_EXPONENTIAL_H
+/*  This file is part of the Vc library. {{{
+
+    Copyright (C) 2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+    -------------------------------------------------------------------
+
+    The exp implementation is derived from Cephes, which carries the
+    following Copyright notice:
+
+    Cephes Math Library Release 2.2:  June, 1992
+    Copyright 1984, 1987, 1989 by Stephen L. Moshier
+    Direct inquiries to 30 Frost Street, Cambridge, MA 02140
+
+}}}*/
+
+#ifndef VC_COMMON_EXPONENTIAL_H
+#define VC_COMMON_EXPONENTIAL_H
+
+#include "macros.h"
+namespace Vc
+{
+namespace Common
+{
+    using Vc::VC__USE_NAMESPACE::c_log;
+    using Vc::VC__USE_NAMESPACE::Vector;
+    using Vc::VC__USE_NAMESPACE::floor;
+    using Vc::VC__USE_NAMESPACE::ldexp;
+
+    static const float log2_e = 1.44269504088896341f;
+    static const float MAXLOGF = 88.72283905206835f;
+    static const float MINLOGF = -103.278929903431851103f; /* log(2^-149) */
+    static const float MAXNUMF = 3.4028234663852885981170418348451692544e38f;
+
+    template<typename T> struct TypenameForLdexp { typedef Vector<int> Type; };
+    template<> struct TypenameForLdexp<Vc::sfloat> { typedef Vector<short> Type; };
+
+    template<typename T> static inline Vector<T> exp(Vector<T> x) {
+        typedef Vector<T> V;
+        typedef typename V::Mask M;
+        typedef typename TypenameForLdexp<T>::Type I;
+        typedef Const<T> C;
+
+        const M overflow  = x > MAXLOGF;
+        const M underflow = x < MINLOGF;
+
+        // log₂(eˣ) = x * log₂(e) * log₂(2)
+        //          = log₂(2^(x * log₂(e)))
+        // => eˣ = 2^(x * log₂(e))
+        // => n  = ⌊x * log₂(e) + ½⌋
+        // => y  = x - n * ln(2)       | recall that: ln(2) * log₂(e) == 1
+        // <=> eˣ = 2ⁿ * eʸ
+        V z = floor(C::log2_e() * x + 0.5f);
+        I n = static_cast<I>(z);
+        x -= z * C::ln2_large();
+        x -= z * C::ln2_small();
+
+        /* Theoretical peak relative error in [-0.5, +0.5] is 4.2e-9. */
+        z = ((((( 1.9875691500E-4f  * x
+                + 1.3981999507E-3f) * x
+                + 8.3334519073E-3f) * x
+                + 4.1665795894E-2f) * x
+                + 1.6666665459E-1f) * x
+                + 5.0000001201E-1f) * (x * x)
+                + x
+                + 1.0f;
+
+        x = ldexp(z, n); // == z * 2ⁿ
+
+        x(overflow) = std::numeric_limits<typename V::EntryType>::infinity();
+        x.setZero(underflow);
+
+        return x;
+    }
+    static inline Vector<double> exp(Vector<double>::AsArg _x) {
+        Vector<double> x = _x;
+        typedef Vector<double> V;
+        typedef V::Mask M;
+        typedef Const<double> C;
+
+        const M overflow  = x > Vc_buildDouble( 1, 0x0006232bdd7abcd2ull, 9); // max log
+        const M underflow = x < Vc_buildDouble(-1, 0x0006232bdd7abcd2ull, 9); // min log
+
+        V px = floor(C::log2_e() * x + 0.5);
+#ifdef VC_IMPL_SSE
+        Vector<int> n(px);
+        n.data() = Mem::permute<X0, X2, X1, X3>(n.data());
+#elif defined(VC_IMPL_AVX)
+        __m128i tmp = _mm256_cvttpd_epi32(px.data());
+        Vector<int> n = AVX::concat(_mm_unpacklo_epi32(tmp, tmp), _mm_unpackhi_epi32(tmp, tmp));
+#endif
+        x -= px * C::ln2_large(); //Vc_buildDouble(1, 0x00062e4000000000ull, -1);  // ln2
+        x -= px * C::ln2_small(); //Vc_buildDouble(1, 0x0007f7d1cf79abcaull, -20); // ln2
+
+        const double P[] = {
+            Vc_buildDouble(1, 0x000089cdd5e44be8ull, -13),
+            Vc_buildDouble(1, 0x000f06d10cca2c7eull,  -6),
+            Vc_buildDouble(1, 0x0000000000000000ull,   0)
+        };
+        const double Q[] = {
+            Vc_buildDouble(1, 0x00092eb6bc365fa0ull, -19),
+            Vc_buildDouble(1, 0x0004ae39b508b6c0ull,  -9),
+            Vc_buildDouble(1, 0x000d17099887e074ull,  -3),
+            Vc_buildDouble(1, 0x0000000000000000ull,   1)
+        };
+        const V x2 = x * x;
+        px = x * ((P[0] * x2 + P[1]) * x2 + P[2]);
+        x =  px / ((((Q[0] * x2 + Q[1]) * x2 + Q[2]) * x2 + Q[3]) - px);
+        x = V::One() + 2.0 * x;
+
+        x = ldexp(x, n); // == x * 2ⁿ
+
+        x(overflow) = std::numeric_limits<double>::infinity();
+        x.setZero(underflow);
+
+        return x;
+    }
+} // namespace Common
+namespace VC__USE_NAMESPACE
+{
+    using Vc::Common::exp;
+} // namespace VC__USE_NAMESPACE
+} // namespace Vc
+#include "undomacros.h"
+
+#endif // VC_COMMON_EXPONENTIAL_H
+#endif // COMMON_EXPONENTIAL_H
diff --git a/Vc/include/Vc/common/logarithm.h b/Vc/include/Vc/common/logarithm.h
new file mode 100644 (file)
index 0000000..9ad19e7
--- /dev/null
@@ -0,0 +1,275 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* The log implementations are based on code from Julien Pommier which carries the following
+   copyright information:
+ */
+/*
+   Inspired by Intel Approximate Math library, and based on the
+   corresponding algorithms of the cephes math library
+*/
+/* Copyright (C) 2007  Julien Pommier
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  (this is the zlib license)
+*/
+
+#ifndef VC_COMMON_LOGARITHM_H
+#define VC_COMMON_LOGARITHM_H
+
+#include "macros.h"
+namespace Vc
+{
+namespace Common
+{
+#ifdef VC__USE_NAMESPACE
+using Vc::VC__USE_NAMESPACE::Const;
+using Vc::VC__USE_NAMESPACE::Vector;
+#endif
+enum LogarithmBase {
+    BaseE, Base10, Base2
+};
+
+template<LogarithmBase Base>
+struct LogImpl
+{
+    template<typename T> static inline ALWAYS_INLINE void log_series(Vector<T> &VC_RESTRICT x, typename Vector<T>::AsArg exponent) {
+        typedef Vector<T> V;
+        typedef Const<T> C;
+        // Taylor series around x = 2^exponent
+        //   f(x) = ln(x)   → exponent * ln(2) → C::ln2_small + C::ln2_large
+        //  f'(x) =    x⁻¹  →  x               → 1
+        // f''(x) = -  x⁻²  → -x² / 2          → C::_1_2()
+        //        =  2!x⁻³  →  x³ / 3          → C::P(8)
+        //        = -3!x⁻⁴  → -x⁴ / 4          → C::P(7)
+        //        =  4!x⁻⁵  →  x⁵ / 5          → C::P(6)
+        // ...
+        // The high order coefficients are adjusted to reduce the error that occurs from ommission
+        // of higher order terms.
+        // P(0) is the smallest term and |x| < 1 ⇒ |xⁿ| > |xⁿ⁺¹|
+        // The order of additions must go from smallest to largest terms
+        const V x2 = x * x; // 0 → 4
+#ifdef VC_LOG_ILP
+        V y2 = (C::P(6) * /*4 →  8*/ x2 + /* 8 → 11*/ C::P(7) * /*1 → 5*/ x) + /*11 → 14*/ C::P(8);
+        V y0 = (C::P(0) * /*5 →  9*/ x2 + /* 9 → 12*/ C::P(1) * /*2 → 6*/ x) + /*12 → 15*/ C::P(2);
+        V y1 = (C::P(3) * /*6 → 10*/ x2 + /*10 → 13*/ C::P(4) * /*3 → 7*/ x) + /*13 → 16*/ C::P(5);
+        const V x3 = x2 * x;  // 7 → 11
+        const V x6 = x3 * x3; // 11 → 15
+        const V x9 = x6 * x3; // 15 → 19
+        V y = (y0 * /*19 → 23*/ x9 + /*23 → 26*/ y1 * /*16 → 20*/ x6) + /*26 → 29*/ y2 * /*14 → 18*/ x3;
+#elif defined VC_LOG_ILP2
+        /*
+         *                            name start done
+         *  movaps %xmm0, %xmm1     ; x     0     1
+         *  movaps %xmm0, %xmm2     ; x     0     1
+         *  mulps %xmm1, %xmm1      ; x2    1     5 *xmm1
+         *  movaps <P8>, %xmm15     ; y8    1     2
+         *  mulps %xmm1, %xmm2      ; x3    5     9 *xmm2
+         *  movaps %xmm1, %xmm3     ; x2    5     6
+         *  movaps %xmm1, %xmm4     ; x2    5     6
+         *  mulps %xmm3, %xmm3      ; x4    6    10 *xmm3
+         *  movaps %xmm2, %xmm5     ; x3    9    10
+         *  movaps %xmm2, %xmm6     ; x3    9    10
+         *  mulps %xmm2, %xmm4      ; x5    9    13 *xmm4
+         *  movaps %xmm3, %xmm7     ; x4   10    11
+         *  movaps %xmm3, %xmm8     ; x4   10    11
+         *  movaps %xmm3, %xmm9     ; x4   10    11
+         *  mulps %xmm5, %xmm5      ; x6   10    14 *xmm5
+         *  mulps %xmm3, %xmm6      ; x7   11    15 *xmm6
+         *  mulps %xmm7, %xmm7      ; x8   12    16 *xmm7
+         *  movaps %xmm4, %xmm10    ; x5   13    14
+         *  mulps %xmm4, %xmm8      ; x9   13    17 *xmm8
+         *  mulps %xmm5, %xmm10     ; x11  14    18 *xmm10
+         *  mulps %xmm5, %xmm9      ; x10  15    19 *xmm9
+         *  mulps <P0>, %xmm10      ; y0   18    22
+         *  mulps <P1>, %xmm9       ; y1   19    23
+         *  mulps <P2>, %xmm8       ; y2   20    24
+         *  mulps <P3>, %xmm7       ; y3   21    25
+         *  addps %xmm10, %xmm9     ; y    23    26
+         *  addps %xmm9, %xmm8      ; y    26    29
+         *  addps %xmm8, %xmm7      ; y    29    32
+         */
+        const V x3 = x2 * x;  // 4  → 8
+        const V x4 = x2 * x2; // 5  → 9
+        const V x5 = x2 * x3; // 8  → 12
+        const V x6 = x3 * x3; // 9  → 13
+        const V x7 = x4 * x3; // 
+        const V x8 = x4 * x4;
+        const V x9 = x5 * x4;
+        const V x10 = x5 * x5;
+        const V x11 = x5 * x6; // 13 → 17
+        V y = C::P(0) * x11 + C::P(1) * x10 + C::P(2) * x9 + C::P(3) * x8 + C::P(4) * x7
+            + C::P(5) * x6  + C::P(6) * x5  + C::P(7) * x4 + C::P(8) * x3;
+#else
+        V y = C::P(0);
+        unrolled_loop16(i, 1, 9,
+                y = y * x + C::P(i);
+                );
+        y *= x * x2;
+#endif
+        switch (Base) {
+        case BaseE:
+            // ln(2) is split in two parts to increase precision (i.e. ln2_small + ln2_large = ln(2))
+            y += exponent * C::ln2_small();
+            y -= x2 * C::_1_2(); // [0, 0.25[
+            x += y;
+            x += exponent * C::ln2_large();
+            break;
+        case Base10:
+            y += exponent * C::ln2_small();
+            y -= x2 * C::_1_2(); // [0, 0.25[
+            x += y;
+            x += exponent * C::ln2_large();
+            x *= C::log10_e();
+            break;
+        case Base2:
+            {
+                const V x_ = x;
+                x *= C::log2_e();
+                y *= C::log2_e();
+                y -= x_ * x * C::_1_2(); // [0, 0.25[
+                x += y;
+                x += exponent;
+                break;
+            }
+        }
+    }
+
+    static inline ALWAYS_INLINE void log_series(Vector<double> &VC_RESTRICT x, Vector<double>::AsArg exponent) {
+        typedef Vector<double> V;
+        typedef Const<double> C;
+        const V x2 = x * x;
+        V y = C::P(0);
+        V y2 = C::Q(0) + x;
+        unrolled_loop16(i, 1, 5,
+                y = y * x + C::P(i);
+                y2 = y2 * x + C::Q(i);
+                );
+        y2 = x / y2;
+        y = y * x + C::P(5);
+        y = x2 * y * y2;
+        // TODO: refactor the following with the float implementation:
+        switch (Base) {
+        case BaseE:
+            // ln(2) is split in two parts to increase precision (i.e. ln2_small + ln2_large = ln(2))
+            y += exponent * C::ln2_small();
+            y -= x2 * C::_1_2(); // [0, 0.25[
+            x += y;
+            x += exponent * C::ln2_large();
+            break;
+        case Base10:
+            y += exponent * C::ln2_small();
+            y -= x2 * C::_1_2(); // [0, 0.25[
+            x += y;
+            x += exponent * C::ln2_large();
+            x *= C::log10_e();
+            break;
+        case Base2:
+            {
+                const V x_ = x;
+                x *= C::log2_e();
+                y *= C::log2_e();
+                y -= x_ * x * C::_1_2(); // [0, 0.25[
+                x += y;
+                x += exponent;
+                break;
+            }
+        }
+    }
+
+    template<typename T> static inline Vector<T> calc(Vector<T> x) {
+        typedef Vector<T> V;
+        typedef typename V::Mask M;
+        typedef Const<T> C;
+
+        const M invalidMask = x < V::Zero();
+        const M infinityMask = x == V::Zero();
+        const M denormal = x <= C::min();
+
+        x(denormal) *= V(Vc_buildDouble(1, 0, 54)); // 2²⁵
+        V exponent = x.exponent(); // = ⎣log₂(x)⎦
+        exponent(denormal) -= 54;
+
+        x.setZero(C::exponentMask()); // keep only the fractional part ⇒ x ∈ [1, 2[
+        x |= C::_1_2();               // and set the exponent to 2⁻¹   ⇒ x ∈ [½, 1[
+
+        // split calculation in two cases:
+        // A: x ∈ [½, √½[
+        // B: x ∈ [√½, 1[
+        // √½ defines the point where Δe(x) := log₂(x) - ⎣log₂(x)⎦ = ½, i.e.
+        // log₂(√½) - ⎣log₂(√½)⎦ = ½ * -1 - ⎣½ * -1⎦ = -½ + 1 = ½
+
+        const M smallX = x < C::_1_sqrt2();
+        x(smallX) += x; // => x ∈ [√½,     1[ ∪ [1.5, 1 + √½[
+        x -= V::One();  // => x ∈ [√½ - 1, 0[ ∪ [0.5, √½[
+        exponent(!smallX) += V::One();
+
+        log_series(x, exponent); // A: (ˣ⁄₂ᵉ - 1, e)  B: (ˣ⁄₂ᵉ⁺¹ - 1, e + 1)
+
+        x.setQnan(invalidMask);        // x < 0 → NaN
+        x(infinityMask) = C::neginf(); // x = 0 → -∞
+
+        return x;
+    }
+};
+
+template<typename T> static inline Vector<T> log(Vector<T> x) {
+    typedef typename Vector<T>::Mask M;
+    typedef Const<T> C;
+    return LogImpl<BaseE>::calc(x);
+}
+template<typename T> static inline Vector<T> log10(Vector<T> x) {
+    typedef typename Vector<T>::Mask M;
+    typedef Const<T> C;
+    return LogImpl<Base10>::calc(x);
+}
+template<typename T> static inline Vector<T> log2(Vector<T> x) {
+    typedef typename Vector<T>::Mask M;
+    typedef Const<T> C;
+    return LogImpl<Base2>::calc(x);
+}
+} // namespace Common
+#ifdef VC__USE_NAMESPACE
+namespace VC__USE_NAMESPACE
+{
+    using Vc::Common::log;
+    using Vc::Common::log10;
+    using Vc::Common::log2;
+} // namespace VC__USE_NAMESPACE
+#undef VC__USE_NAMESPACE
+#endif
+} // namespace Vc
+#include "undomacros.h"
+
+#endif // VC_COMMON_LOGARITHM_H
diff --git a/Vc/include/Vc/common/macros.h b/Vc/include/Vc/common/macros.h
new file mode 100644 (file)
index 0000000..cd4fc75
--- /dev/null
@@ -0,0 +1,307 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2010-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_COMMON_MACROS_H
+#define VC_COMMON_MACROS_H
+#undef VC_COMMON_UNDOMACROS_H
+
+#include <Vc/global.h>
+
+#ifdef VC_MSVC
+# define ALIGN(n) __declspec(align(n))
+# define STRUCT_ALIGN1(n) ALIGN(n)
+# define STRUCT_ALIGN2(n)
+# define ALIGNED_TYPEDEF(n, _type_, _newType_) typedef ALIGN(n) _type_ _newType_
+#else
+# define ALIGN(n) __attribute__((aligned(n)))
+# define STRUCT_ALIGN1(n)
+# define STRUCT_ALIGN2(n) ALIGN(n)
+# define ALIGNED_TYPEDEF(n, _type_, _newType_) typedef _type_ _newType_ ALIGN(n)
+#endif
+
+#define FREE_STORE_OPERATORS_ALIGNED(alignment) \
+        void *operator new(size_t size) { return _mm_malloc(size, alignment); } \
+        void *operator new(size_t, void *p) { return p; } \
+        void *operator new[](size_t size) { return _mm_malloc(size, alignment); } \
+        void operator delete(void *ptr, size_t) { _mm_free(ptr); } \
+        void operator delete[](void *ptr, size_t) { _mm_free(ptr); }
+
+#ifdef VC_CLANG
+#  define INTRINSIC __attribute__((always_inline))
+#  define INTRINSIC_L
+#  define INTRINSIC_R INTRINSIC
+#  define FLATTEN
+#  define CONST __attribute__((const))
+#  define CONST_L
+#  define CONST_R CONST
+#  define PURE __attribute__((pure))
+#  define PURE_L
+#  define PURE_R PURE
+#  define MAY_ALIAS __attribute__((may_alias))
+#  define ALWAYS_INLINE __attribute__((always_inline))
+#  define ALWAYS_INLINE_L
+#  define ALWAYS_INLINE_R ALWAYS_INLINE
+#  define VC_IS_UNLIKELY(x) __builtin_expect(x, 0)
+#  define VC_IS_LIKELY(x) __builtin_expect(x, 1)
+#  define VC_RESTRICT __restrict__
+#elif defined(__GNUC__)
+#  if defined(VC_OPEN64)
+#    define INTRINSIC __attribute__((__flatten__, __always_inline__))
+#  else
+#    define INTRINSIC __attribute__((__flatten__, __always_inline__, __artificial__))
+#  endif
+#  define INTRINSIC_L
+#  define INTRINSIC_R INTRINSIC
+#  define FLATTEN __attribute__((__flatten__))
+#  define CONST __attribute__((__const__))
+#  define CONST_L
+#  define CONST_R CONST
+#  define PURE __attribute__((__pure__))
+#  define PURE_L
+#  define PURE_R PURE
+#  define MAY_ALIAS __attribute__((__may_alias__))
+#  define ALWAYS_INLINE __attribute__((__always_inline__))
+#  define ALWAYS_INLINE_L
+#  define ALWAYS_INLINE_R ALWAYS_INLINE
+#  define VC_IS_UNLIKELY(x) __builtin_expect(x, 0)
+#  define VC_IS_LIKELY(x) __builtin_expect(x, 1)
+#  define VC_RESTRICT __restrict__
+#else
+#  define FLATTEN
+#  ifdef PURE
+#    undef PURE
+#  endif
+#  define MAY_ALIAS
+#  ifdef VC_MSVC
+#    define ALWAYS_INLINE __forceinline
+#    define ALWAYS_INLINE_L ALWAYS_INLINE
+#    define ALWAYS_INLINE_R
+#    define CONST __declspec(noalias)
+#    define CONST_L CONST
+#    define CONST_R
+#    define PURE /*CONST*/
+#    define PURE_L PURE
+#    define PURE_R
+#    define INTRINSIC __forceinline
+#    define INTRINSIC_L INTRINSIC
+#    define INTRINSIC_R
+#  else
+#    define ALWAYS_INLINE
+#    define ALWAYS_INLINE_L
+#    define ALWAYS_INLINE_R
+#    define CONST
+#    define CONST_L
+#    define CONST_R
+#    define PURE
+#    define PURE_L
+#    define PURE_R
+#    define INTRINSIC
+#    define INTRINSIC_L
+#    define INTRINSIC_R
+#  endif
+#  define VC_IS_UNLIKELY(x) x
+#  define VC_IS_LIKELY(x) x
+#  define VC_RESTRICT __restrict
+#endif
+
+#if __cplusplus >= 201103 /*C++11*/
+#define _VC_CONSTEXPR constexpr
+#define _VC_CONSTEXPR_L _VC_CONSTEXPR
+#define _VC_CONSTEXPR_R
+#else
+#define _VC_CONSTEXPR inline INTRINSIC CONST
+#define _VC_CONSTEXPR_L inline INTRINSIC_L CONST_R
+#define _VC_CONSTEXPR_R INTRINSIC_R CONST_R
+#endif
+
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && VC_GCC >= 0x40600) || __cplusplus >= 201103
+# define _VC_NOEXCEPT noexcept
+#else
+# define _VC_NOEXCEPT throw()
+#endif
+
+
+#ifdef VC_GCC
+# define VC_WARN_INLINE
+# define VC_WARN(msg) __attribute__((warning("\n\t" msg)))
+#else
+# define VC_WARN_INLINE inline
+# define VC_WARN(msg)
+#endif
+
+#define unrolled_loop16(_it_, _start_, _end_, _code_) \
+if (_start_ +  0 < _end_) { enum { _it_ = (_start_ +  0) < _end_ ? (_start_ +  0) : _start_ }; _code_ } \
+if (_start_ +  1 < _end_) { enum { _it_ = (_start_ +  1) < _end_ ? (_start_ +  1) : _start_ }; _code_ } \
+if (_start_ +  2 < _end_) { enum { _it_ = (_start_ +  2) < _end_ ? (_start_ +  2) : _start_ }; _code_ } \
+if (_start_ +  3 < _end_) { enum { _it_ = (_start_ +  3) < _end_ ? (_start_ +  3) : _start_ }; _code_ } \
+if (_start_ +  4 < _end_) { enum { _it_ = (_start_ +  4) < _end_ ? (_start_ +  4) : _start_ }; _code_ } \
+if (_start_ +  5 < _end_) { enum { _it_ = (_start_ +  5) < _end_ ? (_start_ +  5) : _start_ }; _code_ } \
+if (_start_ +  6 < _end_) { enum { _it_ = (_start_ +  6) < _end_ ? (_start_ +  6) : _start_ }; _code_ } \
+if (_start_ +  7 < _end_) { enum { _it_ = (_start_ +  7) < _end_ ? (_start_ +  7) : _start_ }; _code_ } \
+if (_start_ +  8 < _end_) { enum { _it_ = (_start_ +  8) < _end_ ? (_start_ +  8) : _start_ }; _code_ } \
+if (_start_ +  9 < _end_) { enum { _it_ = (_start_ +  9) < _end_ ? (_start_ +  9) : _start_ }; _code_ } \
+if (_start_ + 10 < _end_) { enum { _it_ = (_start_ + 10) < _end_ ? (_start_ + 10) : _start_ }; _code_ } \
+if (_start_ + 11 < _end_) { enum { _it_ = (_start_ + 11) < _end_ ? (_start_ + 11) : _start_ }; _code_ } \
+if (_start_ + 12 < _end_) { enum { _it_ = (_start_ + 12) < _end_ ? (_start_ + 12) : _start_ }; _code_ } \
+if (_start_ + 13 < _end_) { enum { _it_ = (_start_ + 13) < _end_ ? (_start_ + 13) : _start_ }; _code_ } \
+if (_start_ + 14 < _end_) { enum { _it_ = (_start_ + 14) < _end_ ? (_start_ + 14) : _start_ }; _code_ } \
+if (_start_ + 15 < _end_) { enum { _it_ = (_start_ + 15) < _end_ ? (_start_ + 15) : _start_ }; _code_ } \
+do {} while ( false )
+
+#define for_all_vector_entries(_it_, _code_) \
+  unrolled_loop16(_it_, 0, Size, _code_)
+
+#ifdef NDEBUG
+#define VC_ASSERT(x)
+#else
+#include <assert.h>
+#define VC_ASSERT(x) assert(x);
+#endif
+
+#ifdef VC_CLANG
+#define VC_HAS_BUILTIN(x) __has_builtin(x)
+#else
+#define VC_HAS_BUILTIN(x) 0
+#endif
+
+#ifndef VC_COMMON_MACROS_H_ONCE
+#define VC_COMMON_MACROS_H_ONCE
+
+#define _VC_CAT_HELPER(a, b, c, d) a##b##c##d
+#define _VC_CAT(a, b, c, d) _VC_CAT_HELPER(a, b, c, d)
+
+#if __cplusplus >= 201103 /*C++11*/ || VC_MSVC >= 160000000
+#define VC_STATIC_ASSERT_NC(cond, msg) \
+    static_assert(cond, #msg)
+#define VC_STATIC_ASSERT(cond, msg) VC_STATIC_ASSERT_NC(cond, msg)
+#else // C++98
+namespace Vc {
+    namespace {
+        template<bool> struct STATIC_ASSERT_FAILURE;
+        template<> struct STATIC_ASSERT_FAILURE<true> {};
+}}
+
+#define VC_STATIC_ASSERT_NC(cond, msg) \
+    typedef STATIC_ASSERT_FAILURE<cond> _VC_CAT(static_assert_failed_on_line_,__LINE__,_,msg); \
+    enum { \
+        _VC_CAT(static_assert_failed__on_line_,__LINE__,_,msg) = sizeof(_VC_CAT(static_assert_failed_on_line_,__LINE__,_,msg)) \
+    }
+#define VC_STATIC_ASSERT(cond, msg) VC_STATIC_ASSERT_NC(cond, msg)
+#endif // C++11/98
+
+    template<int e, int center> struct exponentToMultiplier { enum {
+        X = exponentToMultiplier<e - 1, center>::X * ((e - center < 31) ? 2 : 1),
+        Value = (X == 0 ? 1 : X)
+    }; };
+    template<int center> struct exponentToMultiplier<center,center> { enum { X = 1, Value = X }; };
+    template<int center> struct exponentToMultiplier<   -1, center> { enum { X = 0 }; };
+    template<int center> struct exponentToMultiplier< -256, center> { enum { X = 0 }; };
+    template<int center> struct exponentToMultiplier< -512, center> { enum { X = 0 }; };
+    template<int center> struct exponentToMultiplier<-1024, center> { enum { X = 0 }; };
+
+    template<int e> struct exponentToDivisor { enum {
+        X = exponentToDivisor<e + 1>::X * 2,
+      Value = (X == 0 ? 1 : X)
+    }; };
+    template<> struct exponentToDivisor<0> { enum { X = 1, Value = X }; };
+    template<> struct exponentToDivisor<256> { enum { X = 0 }; };
+    template<> struct exponentToDivisor<512> { enum { X = 0 }; };
+    template<> struct exponentToDivisor<1024> { enum { X = 0 }; };
+#endif // VC_COMMON_MACROS_H_ONCE
+
+#define _CAT_IMPL(a, b) a##b
+#define CAT(a, b) _CAT_IMPL(a, b)
+
+#define Vc_buildDouble(sign, mantissa, exponent) \
+    ((static_cast<double>((mantissa & 0x000fffffffffffffull) | 0x0010000000000000ull) / 0x0010000000000000ull) \
+    * exponentToMultiplier<exponent, 0>::Value \
+    * exponentToMultiplier<exponent, 30>::Value \
+    * exponentToMultiplier<exponent, 60>::Value \
+    * exponentToMultiplier<exponent, 90>::Value \
+    / exponentToDivisor<exponent>::Value \
+    * static_cast<double>(sign))
+#define Vc_buildFloat(sign, mantissa, exponent) \
+    ((static_cast<float>((mantissa & 0x007fffffu) | 0x00800000) / 0x00800000) \
+    * exponentToMultiplier<exponent, 0>::Value \
+    * exponentToMultiplier<exponent, 30>::Value \
+    * exponentToMultiplier<exponent, 60>::Value \
+    * exponentToMultiplier<exponent, 90>::Value \
+    / exponentToDivisor<exponent>::Value \
+    * static_cast<float>(sign))
+
+#define _VC_APPLY_IMPL_1(macro, a, b, c, d, e) macro(a)
+#define _VC_APPLY_IMPL_2(macro, a, b, c, d, e) macro(a, b)
+#define _VC_APPLY_IMPL_3(macro, a, b, c, d, e) macro(a, b, c)
+#define _VC_APPLY_IMPL_4(macro, a, b, c, d, e) macro(a, b, c, d)
+#define _VC_APPLY_IMPL_5(macro, a, b, c, d, e) macro(a, b, c, d, e)
+
+#define VC_LIST_FLOAT_VECTOR_TYPES(size, macro, a, b, c, d) \
+    size(macro, double_v, a, b, c, d) \
+    size(macro,  float_v, a, b, c, d) \
+    size(macro, sfloat_v, a, b, c, d)
+#define VC_LIST_INT_VECTOR_TYPES(size, macro, a, b, c, d) \
+    size(macro,    int_v, a, b, c, d) \
+    size(macro,   uint_v, a, b, c, d) \
+    size(macro,  short_v, a, b, c, d) \
+    size(macro, ushort_v, a, b, c, d)
+#define VC_LIST_VECTOR_TYPES(size, macro, a, b, c, d) \
+    VC_LIST_FLOAT_VECTOR_TYPES(size, macro, a, b, c, d) \
+    VC_LIST_INT_VECTOR_TYPES(size, macro, a, b, c, d)
+#define VC_LIST_COMPARES(size, macro, a, b, c, d) \
+    size(macro, ==, a, b, c, d) \
+    size(macro, !=, a, b, c, d) \
+    size(macro, <=, a, b, c, d) \
+    size(macro, >=, a, b, c, d) \
+    size(macro, < , a, b, c, d) \
+    size(macro, > , a, b, c, d)
+#define VC_LIST_LOGICAL(size, macro, a, b, c, d) \
+    size(macro, &&, a, b, c, d) \
+    size(macro, ||, a, b, c, d)
+#define VC_LIST_BINARY(size, macro, a, b, c, d) \
+    size(macro, |, a, b, c, d) \
+    size(macro, &, a, b, c, d) \
+    size(macro, ^, a, b, c, d)
+#define VC_LIST_SHIFTS(size, macro, a, b, c, d) \
+    size(macro, <<, a, b, c, d) \
+    size(macro, >>, a, b, c, d)
+#define VC_LIST_ARITHMETICS(size, macro, a, b, c, d) \
+    size(macro, +, a, b, c, d) \
+    size(macro, -, a, b, c, d) \
+    size(macro, *, a, b, c, d) \
+    size(macro, /, a, b, c, d) \
+    size(macro, %, a, b, c, d)
+
+#define VC_APPLY_0(_list, macro)             _list(_VC_APPLY_IMPL_1, macro, 0, 0, 0, 0)
+#define VC_APPLY_1(_list, macro, a)          _list(_VC_APPLY_IMPL_2, macro, a, 0, 0, 0)
+#define VC_APPLY_2(_list, macro, a, b)       _list(_VC_APPLY_IMPL_3, macro, a, b, 0, 0)
+#define VC_APPLY_3(_list, macro, a, b, c)    _list(_VC_APPLY_IMPL_4, macro, a, b, c, 0)
+#define VC_APPLY_4(_list, macro, a, b, c, d) _list(_VC_APPLY_IMPL_5, macro, a, b, c, d)
+
+#define VC_ALL_COMPARES(macro)     VC_APPLY_0(VC_LIST_COMPARES, macro)
+#define VC_ALL_LOGICAL(macro)      VC_APPLY_0(VC_LIST_LOGICAL, macro)
+#define VC_ALL_BINARY(macro)       VC_APPLY_0(VC_LIST_BINARY, macro)
+#define VC_ALL_SHIFTS(macro)       VC_APPLY_0(VC_LIST_SHIFTS, macro)
+#define VC_ALL_ARITHMETICS(macro)  VC_APPLY_0(VC_LIST_ARITHMETICS, macro)
+#define VC_ALL_FLOAT_VECTOR_TYPES(macro) VC_APPLY_0(VC_LIST_FLOAT_VECTOR_TYPES, macro)
+#define VC_ALL_VECTOR_TYPES(macro) VC_APPLY_0(VC_LIST_VECTOR_TYPES, macro)
+
+#define VC_EXACT_TYPE(_test, _reference, _type) \
+    typename EnableIf<IsEqualType<_test, _reference>::Value, _type>::Value
+
+#endif // VC_COMMON_MACROS_H
diff --git a/Vc/include/Vc/common/memory.h b/Vc/include/Vc/common/memory.h
new file mode 100644 (file)
index 0000000..26f8dfb
--- /dev/null
@@ -0,0 +1,532 @@
+/*  This file is part of the Vc library.
+
+    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
+
+    Vc is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    Vc is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VC_COMMON_MEMORY_H
+#define VC_COMMON_MEMORY_H
+
+#include "memorybase.h"
+#include <assert.h>
+#include <algorithm>
+#include <cstring>
+#include "memoryfwd.h"
+#include "macros.h"
+
+namespace Vc
+{
+
+/**
+ * Allocates memory on the Heap with alignment and padding.
+ *
+ * Memory that was allocated with this function must be released with Vc::free! Other methods might
+ * work but are not portable.
+ *
+ * \param n Specifies the number of scalar values the allocated memory must be able to store.
+ *
+ * \return Pointer to memory of the requested type and size, or 0 on error.
+ *
+ * \warning The standard malloc function specifies the number of Bytes to allocate whereas this
+ *          function specifies the number of values, thus differing in a factor of sizeof(T)
+ *
+ * \see Vc::free
+ *
+ * \ingroup Utilities
+ * \headerfile memory.h <Vc/Memory>
+ */
+template<typename T, Vc::MallocAlignment A>
+inline ALWAYS_INLINE_L T *ALWAYS_INLINE_R malloc(size_t n)
+{
+    return static_cast<T *>(Internal::Helper::malloc<A>(n * sizeof(T)));
+}
+
+/**
+ * Frees memory that was allocated with Vc::malloc.
+ *
+ * \ingroup Utilities
+ * \headerfile memory.h <Vc/Memory>
+ */
+template<typename T>
+inline void ALWAYS_INLINE free(T *p)
+{
+    Internal::Helper::free(p);
+}
+
+template<typename V, size_t Size> struct _MemorySizeCalculation
+{
+    enum AlignmentCalculations {
+        Alignment = V::Size,
+        AlignmentMask = Alignment - 1,
+        MaskedSize = Size & AlignmentMask,
+        Padding = Alignment - MaskedSize,
+        PaddedSize = MaskedSize == 0 ? Size : Size + Padding
+    };
+};
+
+/**
+ * \ingroup Utilities
+ * \headerfile memory.h <Vc/Memory>
+ *
+ * A helper class for fixed-size two-dimensional arrays.
+ *
+ * \param V The vector type you want to operate on. (e.g. float_v or uint_v)
+ * \param Size1 Number of rows
+ * \param Size2 Number of columns
+ */
+template<typename V, size_t Size1, size_t Size2> class Memory : public VectorAlignedBaseT<V>, public MemoryBase<V, Memory<V, Size1, Size2>, 2, Memory<V, Size2> >
+{
+    public:
+        typedef typename V::EntryType EntryType;
+    private:
+        typedef MemoryBase<V, Memory<V, Size1, Size2>, 2, Memory<V, Size2> > Base;
+            friend class MemoryBase<V, Memory<V, Size1, Size2>, 2, Memory<V, Size2> >;
+            friend class MemoryDimensionBase<V, Memory<V, Size1, Size2>, 2, Memory<V, Size2> >;
+            enum InternalConstants {
+                PaddedSize2 = _MemorySizeCalculation<V, Size2>::PaddedSize
+            };
+#if defined(VC_ICC) && defined(_WIN32)
+            __declspec(align(__alignof(VectorAlignedBaseT<V>)))
+#elif defined(VC_CLANG)
+            __attribute__((aligned(__alignof(VectorAlignedBaseT<V>))))
+#endif
+            EntryType m_mem[Size1][PaddedSize2];
+        public:
+            using Base::vector;
+            enum Constants {
+                RowCount = Size1,
+                VectorsCount = PaddedSize2 / V::Size
+            };
+
+            /**
+             * \return the number of rows in the array.
+             *
+             * \note This function can be eliminated by an optimizing compiler.
+             */
+            inline size_t rowsCount() const { return RowCount; }
+            /**
+             * \return the number of scalar entries in the whole array.
+             *
+             * \warning Do not use this function for scalar iteration over the array since there will be
+             * padding between rows if \c Size2 is not divisible by \c V::Size.
+             *
+             * \note This function can be optimized into a compile-time constant.
+             */
+            inline size_t entriesCount() const { return Size1 * Size2; }
+            /**
+             * \return the number of vectors in the whole array.
+     &nbs