Browse Source

Upgrade Embree to the latest official release.

Since Embree v3.13.0 supports AARCH64, switch back to the
official repo instead of using Embree-aarch64.

`thirdparty/embree/patches/godot-changes.patch` should now contain
an accurate diff of the changes done to the library.
jfons 4 years ago
parent
commit
767e374dce
100 changed files with 7961 additions and 6913 deletions
  1. 2 2
      COPYRIGHT.txt
  2. 6 12
      modules/raycast/SCsub
  3. 1 2
      modules/raycast/config.py
  4. 4 13
      modules/raycast/godot_update_embree.py
  5. 4 4
      thirdparty/README.md
  6. 0 56
      thirdparty/embree-aarch64/common/algorithms/parallel_filter.cpp
  7. 0 48
      thirdparty/embree-aarch64/common/algorithms/parallel_for.cpp
  8. 0 63
      thirdparty/embree-aarch64/common/algorithms/parallel_for_for.cpp
  9. 0 85
      thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.cpp
  10. 0 47
      thirdparty/embree-aarch64/common/algorithms/parallel_map.cpp
  11. 0 53
      thirdparty/embree-aarch64/common/algorithms/parallel_partition.cpp
  12. 0 48
      thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.cpp
  13. 0 49
      thirdparty/embree-aarch64/common/algorithms/parallel_reduce.cpp
  14. 0 43
      thirdparty/embree-aarch64/common/algorithms/parallel_set.cpp
  15. 0 50
      thirdparty/embree-aarch64/common/algorithms/parallel_sort.cpp
  16. 0 986
      thirdparty/embree-aarch64/common/math/AVX2NEON.h
  17. 0 1753
      thirdparty/embree-aarch64/common/math/SSE2NEON.h
  18. 0 61
      thirdparty/embree-aarch64/common/math/constants.cpp
  19. 0 49
      thirdparty/embree-aarch64/common/tasking/taskschedulergcd.h
  20. 0 28
      thirdparty/embree-aarch64/kernels/builders/primrefgen.h
  21. 0 199
      thirdparty/embree-aarch64/kernels/common/instance_stack.h
  22. 0 341
      thirdparty/embree-aarch64/kernels/common/scene_curves.h
  23. 0 21
      thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bezier_curve.h
  24. 0 21
      thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bspline_curve.h
  25. 0 21
      thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_catmullrom_curve.h
  26. 0 21
      thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_hermite_curve.h
  27. 0 21
      thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_linear_curve.h
  28. 0 22
      thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_point.h
  29. 0 493
      thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_moeller.h
  30. 0 508
      thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_pluecker.h
  31. 1 1
      thirdparty/embree/common/algorithms/parallel_any_of.h
  32. 1 1
      thirdparty/embree/common/algorithms/parallel_filter.h
  33. 15 58
      thirdparty/embree/common/algorithms/parallel_for.h
  34. 1 1
      thirdparty/embree/common/algorithms/parallel_for_for.h
  35. 1 1
      thirdparty/embree/common/algorithms/parallel_for_for_prefix_sum.h
  36. 1 1
      thirdparty/embree/common/algorithms/parallel_map.h
  37. 1 1
      thirdparty/embree/common/algorithms/parallel_partition.h
  38. 1 1
      thirdparty/embree/common/algorithms/parallel_prefix_sum.h
  39. 2 2
      thirdparty/embree/common/algorithms/parallel_reduce.h
  40. 1 1
      thirdparty/embree/common/algorithms/parallel_set.h
  41. 3 6
      thirdparty/embree/common/algorithms/parallel_sort.h
  42. 1 1
      thirdparty/embree/common/lexers/parsestream.h
  43. 1 1
      thirdparty/embree/common/lexers/stream.h
  44. 1 1
      thirdparty/embree/common/lexers/streamfilters.h
  45. 1 1
      thirdparty/embree/common/lexers/stringstream.cpp
  46. 1 1
      thirdparty/embree/common/lexers/stringstream.h
  47. 1 1
      thirdparty/embree/common/lexers/tokenstream.cpp
  48. 1 1
      thirdparty/embree/common/lexers/tokenstream.h
  49. 1 1
      thirdparty/embree/common/math/affinespace.h
  50. 4 4
      thirdparty/embree/common/math/bbox.h
  51. 2 2
      thirdparty/embree/common/math/col3.h
  52. 2 2
      thirdparty/embree/common/math/col4.h
  53. 14 30
      thirdparty/embree/common/math/color.h
  54. 27 0
      thirdparty/embree/common/math/constants.cpp
  55. 9 51
      thirdparty/embree/common/math/constants.h
  56. 1 1
      thirdparty/embree/common/math/interval.h
  57. 1 1
      thirdparty/embree/common/math/lbbox.h
  58. 1 1
      thirdparty/embree/common/math/linearspace2.h
  59. 1 1
      thirdparty/embree/common/math/linearspace3.h
  60. 29 111
      thirdparty/embree/common/math/math.h
  61. 1 1
      thirdparty/embree/common/math/obbox.h
  62. 1 1
      thirdparty/embree/common/math/quaternion.h
  63. 1 1
      thirdparty/embree/common/math/range.h
  64. 2 2
      thirdparty/embree/common/math/transcendental.h
  65. 4 4
      thirdparty/embree/common/math/vec2.h
  66. 6 22
      thirdparty/embree/common/math/vec2fa.h
  67. 7 19
      thirdparty/embree/common/math/vec3.h
  68. 1 1
      thirdparty/embree/common/math/vec3ba.h
  69. 23 106
      thirdparty/embree/common/math/vec3fa.h
  70. 8 32
      thirdparty/embree/common/math/vec3ia.h
  71. 4 19
      thirdparty/embree/common/math/vec4.h
  72. 50 0
      thirdparty/embree/common/simd/arm/emulation.h
  73. 6996 0
      thirdparty/embree/common/simd/arm/sse2neon.h
  74. 1 1
      thirdparty/embree/common/simd/avx.h
  75. 1 1
      thirdparty/embree/common/simd/avx512.h
  76. 2 2
      thirdparty/embree/common/simd/simd.h
  77. 1 1
      thirdparty/embree/common/simd/sse.cpp
  78. 2 2
      thirdparty/embree/common/simd/sse.h
  79. 42 29
      thirdparty/embree/common/simd/varying.h
  80. 19 10
      thirdparty/embree/common/simd/vboold4_avx.h
  81. 17 1
      thirdparty/embree/common/simd/vboold4_avx512.h
  82. 17 14
      thirdparty/embree/common/simd/vboold8_avx512.h
  83. 17 14
      thirdparty/embree/common/simd/vboolf16_avx512.h
  84. 17 1
      thirdparty/embree/common/simd/vboolf4_avx512.h
  85. 21 30
      thirdparty/embree/common/simd/vboolf4_sse2.h
  86. 18 5
      thirdparty/embree/common/simd/vboolf8_avx.h
  87. 17 1
      thirdparty/embree/common/simd/vboolf8_avx512.h
  88. 18 21
      thirdparty/embree/common/simd/vdouble4_avx.h
  89. 17 22
      thirdparty/embree/common/simd/vdouble8_avx512.h
  90. 25 181
      thirdparty/embree/common/simd/vfloat16_avx512.h
  91. 111 314
      thirdparty/embree/common/simd/vfloat4_sse2.h
  92. 71 160
      thirdparty/embree/common/simd/vfloat8_avx.h
  93. 19 37
      thirdparty/embree/common/simd/vint16_avx512.h
  94. 80 163
      thirdparty/embree/common/simd/vint4_sse2.h
  95. 52 46
      thirdparty/embree/common/simd/vint8_avx.h
  96. 37 31
      thirdparty/embree/common/simd/vint8_avx2.h
  97. 17 23
      thirdparty/embree/common/simd/vllong4_avx2.h
  98. 18 41
      thirdparty/embree/common/simd/vllong8_avx512.h
  99. 18 37
      thirdparty/embree/common/simd/vuint16_avx512.h
  100. 38 111
      thirdparty/embree/common/simd/vuint4_sse2.h

+ 2 - 2
COPYRIGHT.txt

@@ -131,8 +131,8 @@ Comment: doctest
 Copyright: 2016-2020, Viktor Kirilov
 Copyright: 2016-2020, Viktor Kirilov
 License: Expat
 License: Expat
 
 
-Files: ./thirdparty/embree-aarch64/
-Comment: Embree-aarch64
+Files: ./thirdparty/embree/
+Comment: Embree
 Copyright: 2009-2021 Intel Corporation
 Copyright: 2009-2021 Intel Corporation
 License: Apache-2.0
 License: Apache-2.0
 
 

+ 6 - 12
modules/raycast/SCsub

@@ -10,7 +10,7 @@ env_raycast = env_modules.Clone()
 thirdparty_obj = []
 thirdparty_obj = []
 
 
 if env["builtin_embree"]:
 if env["builtin_embree"]:
-    thirdparty_dir = "#thirdparty/embree-aarch64/"
+    thirdparty_dir = "#thirdparty/embree/"
 
 
     embree_src = [
     embree_src = [
         "common/sys/sysinfo.cpp",
         "common/sys/sysinfo.cpp",
@@ -28,16 +28,6 @@ if env["builtin_embree"]:
         "common/lexers/stringstream.cpp",
         "common/lexers/stringstream.cpp",
         "common/lexers/tokenstream.cpp",
         "common/lexers/tokenstream.cpp",
         "common/tasking/taskschedulerinternal.cpp",
         "common/tasking/taskschedulerinternal.cpp",
-        "common/algorithms/parallel_for.cpp",
-        "common/algorithms/parallel_reduce.cpp",
-        "common/algorithms/parallel_prefix_sum.cpp",
-        "common/algorithms/parallel_for_for.cpp",
-        "common/algorithms/parallel_for_for_prefix_sum.cpp",
-        "common/algorithms/parallel_partition.cpp",
-        "common/algorithms/parallel_sort.cpp",
-        "common/algorithms/parallel_set.cpp",
-        "common/algorithms/parallel_map.cpp",
-        "common/algorithms/parallel_filter.cpp",
         "kernels/common/device.cpp",
         "kernels/common/device.cpp",
         "kernels/common/stat.cpp",
         "kernels/common/stat.cpp",
         "kernels/common/acceln.cpp",
         "kernels/common/acceln.cpp",
@@ -82,13 +72,17 @@ if env["builtin_embree"]:
     if env["platform"] == "windows":
     if env["platform"] == "windows":
         if env.msvc:
         if env.msvc:
             env.Append(LINKFLAGS=["psapi.lib"])
             env.Append(LINKFLAGS=["psapi.lib"])
-            env_raycast.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
         else:
         else:
             env.Append(LIBS=["psapi"])
             env.Append(LIBS=["psapi"])
 
 
     env_thirdparty = env_raycast.Clone()
     env_thirdparty = env_raycast.Clone()
     env_thirdparty.disable_warnings()
     env_thirdparty.disable_warnings()
     env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
     env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+
+    if not env["arch"] in ["x86", "x86_64"] or env.msvc:
+        # Embree needs those, it will automatically use SSE2NEON in ARM
+        env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
+
     env.modules_sources += thirdparty_obj
     env.modules_sources += thirdparty_obj
 
 
 
 

+ 1 - 2
modules/raycast/config.py

@@ -1,6 +1,5 @@
 def can_build(env, platform):
 def can_build(env, platform):
-    # Depends on Embree library, which supports only x86_64 (originally)
-    # and aarch64 (thanks to the embree-aarch64 fork).
+    # Depends on Embree library, which only supports x86_64 and aarch64.
 
 
     if platform == "android":
     if platform == "android":
         return env["android_arch"] in ["arm64v8", "x86_64"]
         return env["android_arch"] in ["arm64v8", "x86_64"]

+ 4 - 13
modules/raycast/godot_update_embree.py

@@ -11,6 +11,7 @@ include_dirs = [
     "common/algorithms",
     "common/algorithms",
     "common/lexers",
     "common/lexers",
     "common/simd",
     "common/simd",
+    "common/simd/arm",
     "include/embree3",
     "include/embree3",
     "kernels/subdiv",
     "kernels/subdiv",
     "kernels/geometry",
     "kernels/geometry",
@@ -32,16 +33,6 @@ cpp_files = [
     "common/lexers/stringstream.cpp",
     "common/lexers/stringstream.cpp",
     "common/lexers/tokenstream.cpp",
     "common/lexers/tokenstream.cpp",
     "common/tasking/taskschedulerinternal.cpp",
     "common/tasking/taskschedulerinternal.cpp",
-    "common/algorithms/parallel_for.cpp",
-    "common/algorithms/parallel_reduce.cpp",
-    "common/algorithms/parallel_prefix_sum.cpp",
-    "common/algorithms/parallel_for_for.cpp",
-    "common/algorithms/parallel_for_for_prefix_sum.cpp",
-    "common/algorithms/parallel_partition.cpp",
-    "common/algorithms/parallel_sort.cpp",
-    "common/algorithms/parallel_set.cpp",
-    "common/algorithms/parallel_map.cpp",
-    "common/algorithms/parallel_filter.cpp",
     "kernels/common/device.cpp",
     "kernels/common/device.cpp",
     "kernels/common/stat.cpp",
     "kernels/common/stat.cpp",
     "kernels/common/acceln.cpp",
     "kernels/common/acceln.cpp",
@@ -74,11 +65,11 @@ cpp_files = [
 
 
 os.chdir("../../thirdparty")
 os.chdir("../../thirdparty")
 
 
-dir_name = "embree-aarch64"
+dir_name = "embree"
 if os.path.exists(dir_name):
 if os.path.exists(dir_name):
     shutil.rmtree(dir_name)
     shutil.rmtree(dir_name)
 
 
-subprocess.run(["git", "clone", "https://github.com/lighttransport/embree-aarch64.git", "embree-tmp"])
+subprocess.run(["git", "clone", "https://github.com/embree/embree.git", "embree-tmp"])
 os.chdir("embree-tmp")
 os.chdir("embree-tmp")
 
 
 commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip()
 commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip()
@@ -197,7 +188,7 @@ with open("CMakeLists.txt", "r") as cmake_file:
 with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as config_file:
 with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as config_file:
     config_file.write(
     config_file.write(
         f"""
         f"""
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 4 - 4
thirdparty/README.md

@@ -61,10 +61,10 @@ Files extracted from upstream source:
 Extracted from .zip provided. Extracted license and header only.
 Extracted from .zip provided. Extracted license and header only.
 
 
 
 
-## embree-aarch64
+## embree
 
 
-- Upstream: https://github.com/lighttransport/embree-aarch64
-- Version: 3.12.1 (6ef362f99af80c9dfe8dd2bfc582d9067897edc6, 2020)
+- Upstream: https://github.com/embree/embree
+- Version: 3.13.0 (7c53133eb21424f7f0ae1e25bf357e358feaf6ab, 2021)
 - License: Apache 2.0
 - License: Apache 2.0
 
 
 Files extracted from upstream:
 Files extracted from upstream:
@@ -73,7 +73,7 @@ Files extracted from upstream:
 - All header files in the directories listed in `modules/raycast/godot_update_embree.py`
 - All header files in the directories listed in `modules/raycast/godot_update_embree.py`
 
 
 The `modules/raycast/godot_update_embree.py` script can be used to pull the
 The `modules/raycast/godot_update_embree.py` script can be used to pull the
-relevant files from the latest Embree-aarch64 release and apply some automatic changes.
+relevant files from the latest Embree release and apply some automatic changes.
 
 
 Some changes have been made in order to remove exceptions and fix minor build errors.
 Some changes have been made in order to remove exceptions and fix minor build errors.
 They are marked with `// -- GODOT start --` and `// -- GODOT end --`
 They are marked with `// -- GODOT start --` and `// -- GODOT end --`

+ 0 - 56
thirdparty/embree-aarch64/common/algorithms/parallel_filter.cpp

@@ -1,56 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_filter.h"
-#include "../sys/regression.h"
-#include <map>
-
-namespace embree
-{
-  struct parallel_filter_regression_test : public RegressionTest
-  {
-    parallel_filter_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-      auto pred = [&]( uint32_t v ) { return (v & 0x3) == 0; };
-      
-      for (size_t N=10; N<1000000; N=size_t(2.1*N))
-      {
-        size_t N0 = rand() % N;
-        
-	/* initialize array with random numbers */
-	std::vector<uint32_t> src(N);
-        std::map<uint32_t,int> m;
-	for (size_t i=0; i<N; i++) src[i] = rand();
-
-        /* count elements up */
-	for (size_t i=N0; i<N; i++)
-          if (pred(src[i]))
-            m[src[i]] = 0;
-        for (size_t i=N0; i<N; i++)
-          if (pred(src[i]))
-            m[src[i]]++;
-
-        /* filter array */
-        //size_t M = sequential_filter(src.data(),N0,N,pred);
-        size_t M = parallel_filter(src.data(),N0,N,size_t(1024),pred);
-        
-	/* check if filtered data is correct */
-	for (size_t i=N0; i<M; i++) {
-          passed &= pred(src[i]);
-          m[src[i]]--;
-        }
-	for (size_t i=N0; i<M; i++)
-          passed &= (m[src[i]] == 0);
-      }
-
-      return passed;
-    }
-  };
-
-  parallel_filter_regression_test parallel_filter_regression("parallel_filter_regression");
-}

+ 0 - 48
thirdparty/embree-aarch64/common/algorithms/parallel_for.cpp

@@ -1,48 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_for.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_for_regression_test : public RegressionTest
-  {
-    parallel_for_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      const size_t M = 10;
-      for (size_t N=10; N<10000000; N=size_t(2.1*N))
-      {
-        /* sequentially calculate sum of squares */
-        size_t sum0 = 0;
-        for (size_t i=0; i<N; i++) {
-          sum0 += i*i;
-        }
-
-        /* parallel calculation of sum of squares */
-        for (size_t m=0; m<M; m++)
-        {
-          std::atomic<size_t> sum1(0);
-          parallel_for( size_t(0), size_t(N), size_t(1024), [&](const range<size_t>& r) 
-          {
-            size_t s = 0;
-            for (size_t i=r.begin(); i<r.end(); i++) 
-              s += i*i;
-            sum1 += s;
-          });
-          passed = sum0 == sum1;
-        }
-      }
-      
-      return passed;
-    }
-  };
-
-  parallel_for_regression_test parallel_for_regression("parallel_for_regression_test");
-}

+ 0 - 63
thirdparty/embree-aarch64/common/algorithms/parallel_for_for.cpp

@@ -1,63 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_for_for.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_for_for_regression_test : public RegressionTest
-  {
-    parallel_for_for_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      /* create vector with random numbers */
-      size_t sum0 = 0;
-      size_t K = 0;
-      const size_t M = 1000;
-      std::vector<std::vector<size_t>* > array2(M);
-      for (size_t i=0; i<M; i++) {
-        const size_t N = rand() % 1024;
-        K+=N;
-        array2[i] = new std::vector<size_t>(N);
-        for (size_t j=0; j<N; j++) 
-          sum0 += (*array2[i])[j] = rand();
-      }
-
-      /* array to test global index */
-      std::vector<atomic<size_t>> verify_k(K);
-      for (size_t i=0; i<K; i++) verify_k[i].store(0);
-
-      /* add all numbers using parallel_for_for */
-      std::atomic<size_t> sum1(0);
-      parallel_for_for( array2, size_t(1), [&](std::vector<size_t>* v, const range<size_t>& r, size_t k) -> size_t
-      {
-        size_t s = 0;
-	for (size_t i=r.begin(); i<r.end(); i++) {
-	  s += (*v)[i];
-          verify_k[k++]++;
-        }
-        sum1 += s;
-	return sum1;
-      });
-      passed &= (sum0 == sum1);
-
-      /* check global index */
-      for (size_t i=0; i<K; i++) 
-        passed &= (verify_k[i] == 1);
-
-      /* delete vectors again */
-      for (size_t i=0; i<array2.size(); i++)
-	delete array2[i];
-      
-      return passed;
-    }
-  };
-
-  parallel_for_for_regression_test parallel_for_for_regression("parallel_for_for_regression_test");
-}

+ 0 - 85
thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.cpp

@@ -1,85 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_for_for_prefix_sum.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_for_for_prefix_sum_regression_test : public RegressionTest
-  {
-    parallel_for_for_prefix_sum_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      /* create vector with random numbers */
-      const size_t M = 10;
-      std::vector<atomic<size_t>> flattened;
-      typedef std::vector<std::vector<size_t>* > ArrayArray;
-      ArrayArray array2(M);
-      size_t K = 0;
-      for (size_t i=0; i<M; i++) {
-        const size_t N = rand() % 10;
-        K += N;
-        array2[i] = new std::vector<size_t>(N);
-        for (size_t j=0; j<N; j++) 
-          (*array2[i])[j] = rand() % 10;
-      }
-  
-      /* array to test global index */
-      std::vector<atomic<size_t>> verify_k(K);
-      for (size_t i=0; i<K; i++) verify_k[i].store(0);
-
-      ParallelForForPrefixSumState<size_t> state(array2,size_t(1));
-  
-      /* dry run only counts */
-      size_t S = parallel_for_for_prefix_sum0( state, array2, size_t(0), [&](std::vector<size_t>* v, const range<size_t>& r, size_t k, size_t i) -> size_t
-      {
-        size_t s = 0;
-	for (size_t i=r.begin(); i<r.end(); i++) {
-          s += (*v)[i];
-          verify_k[k++]++;
-        }
-        return s;
-      }, [](size_t v0, size_t v1) { return v0+v1; });
-      
-      /* create properly sized output array */
-      flattened.resize(S);
-      for (auto& a : flattened) a.store(0);
-
-      /* now we actually fill the flattened array */
-      parallel_for_for_prefix_sum1( state, array2, size_t(0), [&](std::vector<size_t>* v, const range<size_t>& r, size_t k, size_t i, const size_t base) -> size_t
-      {
-        size_t s = 0;
-	for (size_t i=r.begin(); i<r.end(); i++) {
-          for (size_t j=0; j<(*v)[i]; j++) {
-            flattened[base+s+j]++;
-          }
-          s += (*v)[i];
-          verify_k[k++]++;
-        }
-        return s;
-      }, [](size_t v0, size_t v1) { return v0+v1; });
-
-      /* check global index */
-      for (size_t i=0; i<K; i++) 
-        passed &= (verify_k[i] == 2);
-
-      /* check if each element was assigned exactly once */
-      for (size_t i=0; i<flattened.size(); i++)
-        passed &= (flattened[i] == 1);
-      
-      /* delete arrays again */
-      for (size_t i=0; i<array2.size(); i++)
-	delete array2[i];
-
-      return passed;
-    }
-  };
-
-  parallel_for_for_prefix_sum_regression_test parallel_for_for_prefix_sum_regression("parallel_for_for_prefix_sum_regression_test");
-}

+ 0 - 47
thirdparty/embree-aarch64/common/algorithms/parallel_map.cpp

@@ -1,47 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_map.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_map_regression_test : public RegressionTest
-  {
-    parallel_map_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      /* create key/value vectors with random numbers */
-      const size_t N = 10000;
-      std::vector<uint32_t> keys(N);
-      std::vector<uint32_t> vals(N);
-      for (size_t i=0; i<N; i++) keys[i] = 2*unsigned(i)*647382649;
-      for (size_t i=0; i<N; i++) std::swap(keys[i],keys[rand()%N]);
-      for (size_t i=0; i<N; i++) vals[i] = 2*rand();
-      
-      /* create map */
-      parallel_map<uint32_t,uint32_t> map;
-      map.init(keys,vals);
-
-      /* check that all keys are properly mapped */
-      for (size_t i=0; i<N; i++) {
-        const uint32_t* val = map.lookup(keys[i]);
-        passed &= val && (*val == vals[i]);
-      }
-
-      /* check that these keys are not in the map */
-      for (size_t i=0; i<N; i++) {
-        passed &= !map.lookup(keys[i]+1);
-      }
-
-      return passed;
-    }
-  };
-
-  parallel_map_regression_test parallel_map_regression("parallel_map_regression_test");
-}

+ 0 - 53
thirdparty/embree-aarch64/common/algorithms/parallel_partition.cpp

@@ -1,53 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_partition.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_partition_regression_test : public RegressionTest
-  {
-    parallel_partition_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      for (size_t i=0; i<100; i++)
-      {
-        /* create random permutation */
-        size_t N = std::rand() % 1000000;
-        std::vector<unsigned> array(N);
-        for (unsigned i=0; i<N; i++) array[i] = i;
-        for (auto& v : array) std::swap(v,array[std::rand()%array.size()]);
-        size_t split = std::rand() % (N+1);
-
-        /* perform parallel partitioning */
-        size_t left_sum = 0, right_sum = 0;
-        size_t mid = parallel_partitioning(array.data(),0,array.size(),0,left_sum,right_sum,
-                                           [&] ( size_t i ) { return i < split; },
-                                           []  ( size_t& sum, unsigned v) { sum += v; },
-                                           []  ( size_t& sum, size_t v) { sum += v; },
-                                           128);
-        
-        /*serial_partitioning(array.data(),0,array.size(),left_sum,right_sum,
-                            [&] ( size_t i ) { return i < split; },
-                            []  ( size_t& left_sum, int v) { left_sum += v; });*/
-
-        /* verify result */
-        passed &= mid == split;
-        passed &= left_sum == split*(split-1)/2;
-        passed &= right_sum == N*(N-1)/2-left_sum;
-        for (size_t i=0; i<split; i++) passed &= array[i] < split;
-        for (size_t i=split; i<N; i++) passed &= array[i] >= split;
-      }
-      
-      return passed;
-    }
-  };
-
-  parallel_partition_regression_test parallel_partition_regression("parallel_partition_regression_test");
-}

+ 0 - 48
thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.cpp

@@ -1,48 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_prefix_sum.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_prefix_sum_regression_test : public RegressionTest
-  {
-    parallel_prefix_sum_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-      const size_t M = 10;
-      
-      for (size_t N=10; N<10000000; N=size_t(2.1*N))
-      {
-	/* initialize array with random numbers */
-        uint32_t sum0 = 0;
-	std::vector<uint32_t> src(N);
-	for (size_t i=0; i<N; i++) {
-	  sum0 += src[i] = rand();
-        }
-        
-	/* calculate parallel prefix sum */
-	std::vector<uint32_t> dst(N);
-	for (auto& v : dst) v = 0;
-	
-	for (size_t i=0; i<M; i++) {
-	  uint32_t sum1 = parallel_prefix_sum(src,dst,N,0,std::plus<uint32_t>());
-          passed &= (sum0 == sum1);
-        }
-        
-	/* check if prefix sum is correct */
-	for (size_t i=0, sum=0; i<N; sum+=src[i++])
-	  passed &= ((uint32_t)sum == dst[i]);
-      }
-      
-      return passed;
-    }
-  };
-
-  parallel_prefix_sum_regression_test parallel_prefix_sum_regression("parallel_prefix_sum_regression");
-}

+ 0 - 49
thirdparty/embree-aarch64/common/algorithms/parallel_reduce.cpp

@@ -1,49 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_reduce.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_reduce_regression_test : public RegressionTest
-  {
-    parallel_reduce_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      const size_t M = 10;
-      for (size_t N=10; N<10000000; N=size_t(2.1*N))
-      {
-        /* sequentially calculate sum of squares */
-        size_t sum0 = 0;
-        for (size_t i=0; i<N; i++) {
-          sum0 += i*i;
-        }
-
-        /* parallel calculation of sum of squares */
-        for (size_t m=0; m<M; m++)
-        {
-          size_t sum1 = parallel_reduce( size_t(0), size_t(N), size_t(1024), size_t(0), [&](const range<size_t>& r) -> size_t
-          {
-            size_t s = 0;
-            for (size_t i=r.begin(); i<r.end(); i++) 
-              s += i*i;
-            return s;
-          }, 
-          [](const size_t v0, const size_t v1) {
-            return v0+v1;
-          });
-          passed = sum0 == sum1;
-        }
-      }
-      return passed;
-    }
-  };
-
-  parallel_reduce_regression_test parallel_reduce_regression("parallel_reduce_regression_test");
-}

+ 0 - 43
thirdparty/embree-aarch64/common/algorithms/parallel_set.cpp

@@ -1,43 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_set.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  struct parallel_set_regression_test : public RegressionTest
-  {
-    parallel_set_regression_test(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-
-      /* create vector with random numbers */
-      const size_t N = 10000;
-      std::vector<uint32_t> unsorted(N);
-      for (size_t i=0; i<N; i++) unsorted[i] = 2*rand();
-      
-      /* created set from numbers */
-      parallel_set<uint32_t> sorted;
-      sorted.init(unsorted);
-
-      /* check that all elements are in the set */
-      for (size_t i=0; i<N; i++) {
-	passed &= sorted.lookup(unsorted[i]);
-      }
-
-      /* check that these elements are not in the set */
-      for (size_t i=0; i<N; i++) {
-	passed &= !sorted.lookup(unsorted[i]+1);
-      }
-
-      return passed;
-    }
-  };
-
-  parallel_set_regression_test parallel_set_regression("parallel_set_regression_test");
-}

+ 0 - 50
thirdparty/embree-aarch64/common/algorithms/parallel_sort.cpp

@@ -1,50 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#include "parallel_sort.h"
-#include "../sys/regression.h"
-
-namespace embree
-{
-  template<typename Key>
-  struct RadixSortRegressionTest : public RegressionTest
-  {
-    RadixSortRegressionTest(const char* name) : RegressionTest(name) {
-      registerRegressionTest(this);
-    }
-    
-    bool run ()
-    {
-      bool passed = true;
-      const size_t M = 10;
-
-      for (size_t N=10; N<1000000; N=size_t(2.1*N))
-      {
-	std::vector<Key> src(N); memset(src.data(),0,N*sizeof(Key));
-	std::vector<Key> tmp(N); memset(tmp.data(),0,N*sizeof(Key));
-	for (size_t i=0; i<N; i++) src[i] = uint64_t(rand())*uint64_t(rand());
-	
-	/* calculate checksum */
-	Key sum0 = 0; for (size_t i=0; i<N; i++) sum0 += src[i];
-        
-	/* sort numbers */
-	for (size_t i=0; i<M; i++) {
-          radix_sort<Key>(src.data(),tmp.data(),N);
-        }
-	
-	/* calculate checksum */
-	Key sum1 = 0; for (size_t i=0; i<N; i++) sum1 += src[i];
-	if (sum0 != sum1) passed = false;
-        
-	/* check if numbers are sorted */
-	for (size_t i=1; i<N; i++)
-	  passed &= src[i-1] <= src[i];
-      }
-      
-      return passed;
-    }
-  };
-
-  RadixSortRegressionTest<uint32_t> test_u32("RadixSortRegressionTestU32");
-  RadixSortRegressionTest<uint64_t> test_u64("RadixSortRegressionTestU64");
-}

+ 0 - 986
thirdparty/embree-aarch64/common/math/AVX2NEON.h

@@ -1,986 +0,0 @@
-#pragma once
-
-#include "SSE2NEON.h"
-
-
-#define AVX2NEON_ABI static inline  __attribute__((always_inline))
-
-
-struct __m256d;
-
-struct __m256 {
-    __m128 lo,hi;
-    __m256() {}
-};
-
-
-
-
-struct __m256i {
-    __m128i lo,hi;
-    explicit __m256i(const __m256 a) : lo(__m128i(a.lo)),hi(__m128i(a.hi)) {}
-    operator __m256() const {__m256 res; res.lo = __m128(lo);res.hi = __m128(hi); return res;}
-    __m256i() {}
-};
- 
-
-
-
-struct __m256d {
-    float64x2_t lo,hi;
-    __m256d() {}
-    __m256d(const __m256& a) : lo(float64x2_t(a.lo)),hi(float64x2_t(a.hi)) {}
-    __m256d(const __m256i& a) : lo(float64x2_t(a.lo)),hi(float64x2_t(a.hi)) {}
-};
-
-#define UNARY_AVX_OP(type,func,basic_func) AVX2NEON_ABI type func(const type& a) {type res;res.lo=basic_func(a.lo);res.hi=basic_func(a.hi);return res;}
-
-
-#define BINARY_AVX_OP(type,func,basic_func) AVX2NEON_ABI type func(const type& a,const type& b) {type res;res.lo=basic_func(a.lo,b.lo);res.hi=basic_func(a.hi,b.hi);return res;}
-#define BINARY_AVX_OP_CAST(type,func,basic_func,bdst,bsrc) AVX2NEON_ABI type func(const type& a,const type& b) {type res;res.lo=bdst(basic_func(bsrc(a.lo),bsrc(b.lo)));res.hi=bdst(basic_func(bsrc(a.hi),bsrc(b.hi)));return res;}
-
-#define TERNARY_AVX_OP(type,func,basic_func) AVX2NEON_ABI type func(const type& a,const type& b,const type& c) {type res;res.lo=basic_func(a.lo,b.lo,c.lo);res.hi=basic_func(a.hi,b.hi,c.hi);return res;}
-
-
-#define CAST_SIMD_TYPE(to,name,from,basic_dst) AVX2NEON_ABI to name(const from& a) { to res; res.lo = basic_dst(a.lo); res.hi=basic_dst(a.hi); return res;}
-
-
-
-#define _mm_stream_load_si128 _mm_load_si128
-#define _mm256_stream_load_si256 _mm256_load_si256
-
-
-AVX2NEON_ABI
-__m128 _mm_blend_ps (__m128 a, __m128 b, const int imm8)
-{
-    __m128 res;
-    for (int i=0;i<4;i++)
-    {
-        if (imm8 & (1<<i))
-        {
-            res[i] = b[i];
-        }
-        else{
-            res[i] = a[i];
-        }
-    }
-    
-    return res;
-}
-
-AVX2NEON_ABI
-__m128i _mm_blend_epi32 (__m128i a, __m128i b, const int imm8)
-{
-    __m128i res;
-    for (int i=0;i<4;i++)
-    {
-        if (imm8 & (1<<i))
-        {
-            res[i] = b[i];
-        }
-        else{
-            res[i] = a[i];
-        }
-    }
-    return res;
-}
-
-AVX2NEON_ABI
-__m128 _mm_cmpngt_ps (__m128 a, __m128 b)
-{
-    return __m128(vmvnq_s32(__m128i(_mm_cmpgt_ps(a,b))));
-}
-
-
-AVX2NEON_ABI
-__m128i _mm_loadl_epi64 (__m128i const* mem_addr)
-{
-    int64x2_t y;
-    y[0] = *(int64_t *)mem_addr;
-    y[1] = 0;
-    return __m128i(y);
-}
-
-AVX2NEON_ABI
-int _mm_movemask_popcnt(__m128 a)
-{
-    return __builtin_popcount(_mm_movemask_ps(a));
-}
-
-AVX2NEON_ABI
-__m128 _mm_maskload_ps (float const * mem_addr, __m128i mask)
-{
-    __m128 res;
-    for (int i=0;i<4;i++) {
-        if (mask[i] & 0x80000000) res[i] = mem_addr[i]; else res[i] = 0;
-    }
-    return res;
-}
-
-AVX2NEON_ABI
-void _mm_maskstore_ps (float * mem_addr, __m128i mask, __m128 a)
-{
-    for (int i=0;i<4;i++) {
-        if (mask[i] & 0x80000000) mem_addr[i] = a[i];
-    }
-}
-
-AVX2NEON_ABI
-void _mm_maskstore_epi32 (int * mem_addr, __m128i mask, __m128i a)
-{
-    for (int i=0;i<4;i++) {
-        if (mask[i] & 0x80000000) mem_addr[i] = a[i];
-    }
-}
-
-AVX2NEON_ABI
-__m128 _mm_fnmsub_ps (__m128 a, __m128 b, __m128 c)
-{
-    return vnegq_f32(vfmaq_f32(c,a,b));
-}
-
-#define _mm_fnmsub_ss _mm_fnmsub_ps
-
-AVX2NEON_ABI
-__m128 _mm_fnmadd_ps (__m128 a, __m128 b, __m128 c)
-{
-    return vfmsq_f32(c,a,b);
-}
-
-#define _mm_fnmadd_ss _mm_fnmadd_ps
-
-
-AVX2NEON_ABI
-__m128 _mm_broadcast_ss (float const * mem_addr)
-{
-    return vdupq_n_f32(*mem_addr);
-}
-
-
-AVX2NEON_ABI
-__m128 _mm_fmsub_ps (__m128 a, __m128 b, __m128 c)
-{
-    return vfmaq_f32(vnegq_f32(c),a,b);
-}
-
-#define _mm_fmsub_ss _mm_fmsub_ps
-#define _mm_fmadd_ps _mm_madd_ps
-#define _mm_fmadd_ss _mm_madd_ps
-
-
-
-template<int code>
-AVX2NEON_ABI float32x4_t dpps_neon(const float32x4_t& a,const float32x4_t& b)
-{
-    float v;
-    v = 0;
-    v += (code & 0x10) ? a[0]*b[0] : 0;
-    v += (code & 0x20) ? a[1]*b[1] : 0;
-    v += (code & 0x40) ? a[2]*b[2] : 0;
-    v += (code & 0x80) ? a[3]*b[3] : 0;
-    float32x4_t res;
-    res[0] = (code & 0x1) ? v : 0;
-    res[1] = (code & 0x2) ? v : 0;
-    res[2] = (code & 0x4) ? v : 0;
-    res[3] = (code & 0x8) ? v : 0;
-    return res;
-}
-
-template<>
-inline float32x4_t dpps_neon<0x7f>(const float32x4_t& a,const float32x4_t& b)
-{
-    float v;
-    float32x4_t m = _mm_mul_ps(a,b);
-    m[3] = 0;
-    v = vaddvq_f32(m);
-    return _mm_set1_ps(v);
-}
-
-template<>
-inline float32x4_t dpps_neon<0xff>(const float32x4_t& a,const float32x4_t& b)
-{
-    float v;
-    float32x4_t m = _mm_mul_ps(a,b);
-    v = vaddvq_f32(m);
-    return _mm_set1_ps(v);
-}
-
-#define _mm_dp_ps(a,b,c) dpps_neon<c>((a),(b))
-
-
-
-AVX2NEON_ABI
-__m128 _mm_cmpnge_ps (__m128 a, __m128 b)
-{
-    return __m128(vmvnq_s32(__m128i(_mm_cmpge_ps(a,b))));
-}
-
-
-AVX2NEON_ABI
-__m128 _mm_permutevar_ps (__m128 a, __m128i b)
-{
-    __m128 x;
-    for (int i=0;i<4;i++)
-    {
-        x[i] = a[b[i&3]];
-    }
-    return x;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_setzero_si256()
-{
-    __m256i res;
-    res.lo = res.hi = vdupq_n_s32(0);
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_setzero_ps()
-{
-    __m256 res;
-    res.lo = res.hi = vdupq_n_f32(0.0f);
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_undefined_si256()
-{
-    return _mm256_setzero_si256();
-}
-
-AVX2NEON_ABI
-__m256 _mm256_undefined_ps()
-{
-    return _mm256_setzero_ps();
-}
-
-CAST_SIMD_TYPE(__m256d,_mm256_castps_pd,__m256,float64x2_t)
-CAST_SIMD_TYPE(__m256i,_mm256_castps_si256,__m256,__m128i)
-CAST_SIMD_TYPE(__m256, _mm256_castsi256_ps, __m256i,__m128)
-CAST_SIMD_TYPE(__m256, _mm256_castpd_ps ,__m256d,__m128)
-CAST_SIMD_TYPE(__m256d, _mm256_castsi256_pd, __m256i,float64x2_t)
-CAST_SIMD_TYPE(__m256i, _mm256_castpd_si256, __m256d,__m128i)
-
-
-
-
-AVX2NEON_ABI
-__m128 _mm256_castps256_ps128 (__m256 a)
-{
-    return a.lo;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_castsi128_si256 (__m128i a)
-{
-    __m256i res;
-    res.lo = a ;
-    res.hi = vdupq_n_s32(0);
-    return res;
-}
-
-AVX2NEON_ABI
-__m128i _mm256_castsi256_si128 (__m256i a)
-{
-    return a.lo;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_castps128_ps256 (__m128 a)
-{
-    __m256 res;
-    res.lo = a;
-    res.hi = vdupq_n_f32(0);
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256 _mm256_broadcast_ss (float const * mem_addr)
-{
-    __m256 res;
-    res.lo = res.hi = vdupq_n_f32(*mem_addr);
-    return res;
-}
-
-
-
-AVX2NEON_ABI
-__m256i _mm256_set_epi32 (int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
-{
-    __m128i lo = {e0,e1,e2,e3}, hi = {e4,e5,e6,e7};
-    __m256i res;
-    res.lo = lo; res.hi = hi;
-    return res;
-    
-}
-
-AVX2NEON_ABI
-__m256i _mm256_set1_epi32 (int a)
-{
-    __m256i res;
-    res.lo = res.hi = vdupq_n_s32(a);
-    return res;
-}
-
-
-
-
-AVX2NEON_ABI
-int _mm256_movemask_ps(const __m256& v)
-{
-    return (_mm_movemask_ps(v.hi) << 4) | _mm_movemask_ps(v.lo);
-}
-
-template<int imm8>
-AVX2NEON_ABI
-__m256 __mm256_permute_ps (const __m256& a)
-{
-    __m256 res;
-    res.lo = _mm_shuffle_ps(a.lo,a.lo,imm8);
-    res.hi = _mm_shuffle_ps(a.hi,a.hi,imm8);
-    return res;
-
-}
-
-#define _mm256_permute_ps(a,c) __mm256_permute_ps<c>(a)
-
-
-template<int imm8>
-AVX2NEON_ABI
-__m256 __mm256_shuffle_ps (const __m256 a,const __m256& b)
-{
-    __m256 res;
-    res.lo = _mm_shuffle_ps(a.lo,b.lo,imm8);
-    res.hi = _mm_shuffle_ps(a.hi,b.hi,imm8);
-    return res;
-
-}
-
-#define _mm256_shuffle_ps(a,b,c) __mm256_shuffle_ps<c>(a,b)
-
-AVX2NEON_ABI
-__m256i _mm256_set1_epi64x (long long a)
-{
-    __m256i res;
-    int64x2_t t = vdupq_n_s64(a);
-    res.lo = res.hi = __m128i(t);
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256 _mm256_permute2f128_ps (__m256 a, __m256 b, int imm8)
-{
-    __m256 res;
-    __m128 tmp;
-    switch (imm8 & 0x7)
-    {
-        case 0: tmp = a.lo; break;
-        case 1: tmp = a.hi; break;
-        case 2: tmp = b.lo; break;
-        case 3: tmp = b.hi; break;
-    }
-    if (imm8 & 0x8)
-        tmp = _mm_setzero_ps();
-
-    
-    
-    res.lo = tmp;
-    imm8 >>= 4;
-    
-    switch (imm8 & 0x7)
-    {
-        case 0: tmp = a.lo; break;
-        case 1: tmp = a.hi; break;
-        case 2: tmp = b.lo; break;
-        case 3: tmp = b.hi; break;
-    }
-    if (imm8 & 0x8)
-        tmp = _mm_setzero_ps();
-    
-    res.hi = tmp;
-    
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_moveldup_ps (__m256 a)
-{
-    __m256 res;
-    res.lo[0] = res.lo[1] = a.lo[0];
-    res.lo[2] = res.lo[3] = a.lo[2];
-    res.hi[0] = res.hi[1] = a.hi[0];
-    res.hi[2] = res.hi[3] = a.hi[2];
-    return res;
-
-}
-
-AVX2NEON_ABI
-__m256 _mm256_movehdup_ps (__m256 a)
-{
-    __m256 res;
-    res.lo[0] = res.lo[1] = a.lo[1];
-    res.lo[2] = res.lo[3] = a.lo[3];
-    res.hi[0] = res.hi[1] = a.hi[1];
-    res.hi[2] = res.hi[3] = a.hi[3];
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_insertf128_ps (__m256 a, __m128 b, int imm8)
-{
-    __m256 res = a;
-    if (imm8 & 1) res.hi = b;
-    else res.lo = b;
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m128 _mm256_extractf128_ps (__m256 a, const int imm8)
-{
-    if (imm8 & 1) return a.hi;
-    return a.lo;
-}
-
-
-AVX2NEON_ABI
-__m256d _mm256_movedup_pd (__m256d a)
-{
-    __m256d res;
-    res.hi = a.hi;
-    res.lo[0] = res.lo[1] = a.lo[0];
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_abs_epi32(__m256i a)
-{
-   __m256i res;
-   res.lo = vabsq_s32(a.lo);
-   res.hi = vabsq_s32(a.hi);
-   return res;
-}
-
-UNARY_AVX_OP(__m256,_mm256_sqrt_ps,_mm_sqrt_ps)
-UNARY_AVX_OP(__m256,_mm256_rsqrt_ps,_mm_rsqrt_ps)
-UNARY_AVX_OP(__m256,_mm256_rcp_ps,_mm_rcp_ps)
-UNARY_AVX_OP(__m256,_mm256_floor_ps,vrndmq_f32)
-UNARY_AVX_OP(__m256,_mm256_ceil_ps,vrndpq_f32)
-
-
-BINARY_AVX_OP(__m256i,_mm256_add_epi32,_mm_add_epi32)
-BINARY_AVX_OP(__m256i,_mm256_sub_epi32,_mm_sub_epi32)
-BINARY_AVX_OP(__m256i,_mm256_mullo_epi32,_mm_mullo_epi32)
-
-BINARY_AVX_OP(__m256i,_mm256_min_epi32,_mm_min_epi32)
-BINARY_AVX_OP(__m256i,_mm256_max_epi32,_mm_max_epi32)
-BINARY_AVX_OP_CAST(__m256i,_mm256_min_epu32,vminq_u32,__m128i,uint32x4_t)
-BINARY_AVX_OP_CAST(__m256i,_mm256_max_epu32,vmaxq_u32,__m128i,uint32x4_t)
-
-BINARY_AVX_OP(__m256,_mm256_min_ps,_mm_min_ps)
-BINARY_AVX_OP(__m256,_mm256_max_ps,_mm_max_ps)
-
-BINARY_AVX_OP(__m256,_mm256_add_ps,_mm_add_ps)
-BINARY_AVX_OP(__m256,_mm256_mul_ps,_mm_mul_ps)
-BINARY_AVX_OP(__m256,_mm256_sub_ps,_mm_sub_ps)
-BINARY_AVX_OP(__m256,_mm256_div_ps,_mm_div_ps)
-
-BINARY_AVX_OP(__m256,_mm256_and_ps,_mm_and_ps)
-BINARY_AVX_OP(__m256,_mm256_andnot_ps,_mm_andnot_ps)
-BINARY_AVX_OP(__m256,_mm256_or_ps,_mm_or_ps)
-BINARY_AVX_OP(__m256,_mm256_xor_ps,_mm_xor_ps)
-
-BINARY_AVX_OP_CAST(__m256d,_mm256_and_pd,vandq_s64,float64x2_t,int64x2_t)
-BINARY_AVX_OP_CAST(__m256d,_mm256_or_pd,vorrq_s64,float64x2_t,int64x2_t)
-BINARY_AVX_OP_CAST(__m256d,_mm256_xor_pd,veorq_s64,float64x2_t,int64x2_t)
-
-
-
-BINARY_AVX_OP(__m256i,_mm256_and_si256,_mm_and_si128)
-BINARY_AVX_OP(__m256i,_mm256_or_si256,_mm_or_si128)
-BINARY_AVX_OP(__m256i,_mm256_xor_si256,_mm_xor_si128)
-
-
-BINARY_AVX_OP(__m256,_mm256_unpackhi_ps,_mm_unpackhi_ps)
-BINARY_AVX_OP(__m256,_mm256_unpacklo_ps,_mm_unpacklo_ps)
-TERNARY_AVX_OP(__m256,_mm256_blendv_ps,_mm_blendv_ps)
-
-
-TERNARY_AVX_OP(__m256,_mm256_fmadd_ps,_mm_fmadd_ps)
-TERNARY_AVX_OP(__m256,_mm256_fnmadd_ps,_mm_fnmadd_ps)
-TERNARY_AVX_OP(__m256,_mm256_fmsub_ps,_mm_fmsub_ps)
-TERNARY_AVX_OP(__m256,_mm256_fnmsub_ps,_mm_fnmsub_ps)
-
-
-BINARY_AVX_OP(__m256i,_mm256_unpackhi_epi32,_mm_unpackhi_epi32)
-BINARY_AVX_OP(__m256i,_mm256_unpacklo_epi32,_mm_unpacklo_epi32)
-
-
-BINARY_AVX_OP(__m256i,_mm256_cmpeq_epi32,_mm_cmpeq_epi32)
-BINARY_AVX_OP(__m256i,_mm256_cmpgt_epi32,_mm_cmpgt_epi32)
-BINARY_AVX_OP(__m256,_mm256_cmpeq_ps,_mm_cmpeq_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpneq_ps,_mm_cmpneq_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpnlt_ps,_mm_cmpnlt_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpngt_ps,_mm_cmpngt_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpge_ps,_mm_cmpge_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpnge_ps,_mm_cmpnge_ps)
-BINARY_AVX_OP(__m256,_mm256_cmplt_ps,_mm_cmplt_ps)
-BINARY_AVX_OP(__m256,_mm256_cmple_ps,_mm_cmple_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpgt_ps,_mm_cmpgt_ps)
-BINARY_AVX_OP(__m256,_mm256_cmpnle_ps,_mm_cmpnle_ps)
-
-
-AVX2NEON_ABI
-__m256i _mm256_cvtps_epi32 (__m256 a)
-{
-    __m256i res;
-    res.lo = _mm_cvtps_epi32(a.lo);
-    res.hi = _mm_cvtps_epi32(a.hi);
-    return res;
-    
-}
-
-AVX2NEON_ABI
-__m256i _mm256_cvttps_epi32 (__m256 a)
-{
-    __m256i res;
-    res.lo = _mm_cvttps_epi32(a.lo);
-    res.hi = _mm_cvttps_epi32(a.hi);
-    return res;
-    
-}
-
-AVX2NEON_ABI
-__m256 _mm256_loadu_ps (float const * mem_addr)
-{
-    __m256 res;
-    res.lo = *(__m128 *)(mem_addr + 0);
-    res.hi = *(__m128 *)(mem_addr + 4);
-    return res;
-}
-#define _mm256_load_ps _mm256_loadu_ps
-
-
-AVX2NEON_ABI
-int _mm256_testz_ps (const __m256& a, const __m256& b)
-{
-    __m256 t = a;
-    if (&a != &b)
-        t = _mm256_and_ps(a,b);
-
-    __m128i l  = vshrq_n_s32(__m128i(t.lo),31);
-    __m128i h  = vshrq_n_s32(__m128i(t.hi),31);
-    return vaddvq_s32(vaddq_s32(l,h)) == 0;
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_set_epi64x (int64_t e3, int64_t e2, int64_t e1, int64_t e0)
-{
-    __m256i res;
-    int64x2_t t0 = {e0,e1};
-    int64x2_t t1 = {e2,e3};
-    res.lo = __m128i(t0);
-    res.hi = __m128i(t1);
-    return res;
-}
-
-AVX2NEON_ABI
-__m256d _mm256_setzero_pd ()
-{
-    __m256d res;
-    res.lo = res.hi = vdupq_n_f64(0);
-    return res;
-}
-
-AVX2NEON_ABI
-int _mm256_movemask_pd (__m256d a)
-{
-    int res = 0;
-    uint64x2_t x;
-    x = uint64x2_t(a.lo);
-    res |= (x[0] >> 63) ? 1 : 0;
-    res |= (x[0] >> 63) ? 2 : 0;
-    x = uint64x2_t(a.hi);
-    res |= (x[0] >> 63) ? 4 : 0;
-    res |= (x[0] >> 63) ? 8 : 0;
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_cmpeq_epi64 (__m256i a, __m256i b)
-{
-    __m256i res;
-    res.lo = __m128i(vceqq_s64(int64x2_t(a.lo),int64x2_t(b.lo)));
-    res.hi = __m128i(vceqq_s64(int64x2_t(a.hi),int64x2_t(b.hi)));
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_cmpeq_pd (__m256d a, __m256d b)
-{
-    __m256i res;
-    res.lo = __m128i(vceqq_f64(a.lo,b.lo));
-    res.hi = __m128i(vceqq_f64(a.hi,b.hi));
-    return res;
-}
-
-
-AVX2NEON_ABI
-int _mm256_testz_pd (const __m256d& a, const __m256d& b)
-{
-    __m256d t = a;
-
-    if (&a != &b)
-        t = _mm256_and_pd(a,b);
-
-    return _mm256_movemask_pd(t) == 0;
-}
-
-AVX2NEON_ABI
-__m256d _mm256_blendv_pd (__m256d a, __m256d b, __m256d mask)
-{
-    __m256d res;
-    uint64x2_t t = uint64x2_t(mask.lo);
-    res.lo[0] = (t[0] >> 63) ? b.lo[0] : a.lo[0];
-    res.lo[1] = (t[1] >> 63) ? b.lo[1] : a.lo[1];
-    t = uint64x2_t(mask.hi);
-    res.hi[0] = (t[0] >> 63) ? b.hi[0] : a.hi[0];
-    res.hi[1] = (t[1] >> 63) ? b.hi[1] : a.hi[1];
-    return res;
-}
-
-template<int imm8>
-__m256 __mm256_dp_ps (__m256 a, __m256 b)
-{
-    __m256 res;
-    res.lo = _mm_dp_ps(a.lo,b.lo,imm8);
-    res.hi = _mm_dp_ps(a.hi,b.hi,imm8);
-    return res;
-}
-
-#define _mm256_dp_ps(a,b,c) __mm256_dp_ps<c>(a,b)
-
-AVX2NEON_ABI
-double _mm256_permute4x64_pd_select(__m256d a, const int imm8)
-{
-    switch (imm8 & 3) {
-        case 0:
-            return a.lo[0];
-        case 1:
-            return a.lo[1];
-        case 2:
-            return a.hi[0];
-        case 3:
-            return a.hi[1];
-    }
-    __builtin_unreachable();
-    return 0;
-}
-
-AVX2NEON_ABI
-__m256d _mm256_permute4x64_pd (__m256d a, const int imm8)
-{
-    __m256d res;
-    res.lo[0] = _mm256_permute4x64_pd_select(a,imm8 >> 0);
-    res.lo[1] = _mm256_permute4x64_pd_select(a,imm8 >> 2);
-    res.hi[0] = _mm256_permute4x64_pd_select(a,imm8 >> 4);
-    res.hi[1] = _mm256_permute4x64_pd_select(a,imm8 >> 6);
-    
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_insertf128_si256 (__m256i a, __m128i b, int imm8)
-{
-    return __m256i(_mm256_insertf128_ps((__m256)a,(__m128)b,imm8));
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_loadu_si256 (__m256i const * mem_addr)
-{
-    __m256i res;
-    res.lo = *(__m128i *)((int32_t *)mem_addr + 0);
-    res.hi = *(__m128i *)((int32_t *)mem_addr + 4);
-    return res;
-}
-
-#define _mm256_load_si256 _mm256_loadu_si256
-
-AVX2NEON_ABI
-void _mm256_storeu_ps (float * mem_addr, __m256 a)
-{
-    *(__m128 *)(mem_addr + 0) = a.lo;
-    *(__m128 *)(mem_addr + 4) = a.hi;
-
-}
-
-#define _mm256_store_ps _mm256_storeu_ps
-#define _mm256_stream_ps _mm256_storeu_ps
-
-
-AVX2NEON_ABI
-void _mm256_storeu_si256 (__m256i * mem_addr, __m256i a)
-{
-    *(__m128i *)((int *)mem_addr + 0) = a.lo;
-    *(__m128i *)((int *)mem_addr + 4) = a.hi;
-
-}
-
-#define _mm256_store_si256 _mm256_storeu_si256
-
-
-
-AVX2NEON_ABI
-__m256 _mm256_maskload_ps (float const * mem_addr, __m256i mask)
-{
-    __m256 res;
-    res.lo = _mm_maskload_ps(mem_addr,mask.lo);
-    res.hi = _mm_maskload_ps(mem_addr + 4,mask.hi);
-    return res;
-
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_cvtepu8_epi32 (__m128i a)
-{
-    __m256i res;
-    uint8x16_t x = uint8x16_t(a);
-    for (int i=0;i<4;i++)
-    {
-        res.lo[i] = x[i];
-        res.hi[i] = x[i+4];
-    }
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_cvtepi8_epi32 (__m128i a)
-{
-    __m256i res;
-    int8x16_t x = int8x16_t(a);
-    for (int i=0;i<4;i++)
-    {
-        res.lo[i] = x[i];
-        res.hi[i] = x[i+4];
-    }
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_cvtepu16_epi32 (__m128i a)
-{
-    __m256i res;
-    uint16x8_t x = uint16x8_t(a);
-    for (int i=0;i<4;i++)
-    {
-        res.lo[i] = x[i];
-        res.hi[i] = x[i+4];
-    }
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_cvtepi16_epi32 (__m128i a)
-{
-    __m256i res;
-    int16x8_t x = int16x8_t(a);
-    for (int i=0;i<4;i++)
-    {
-        res.lo[i] = x[i];
-        res.hi[i] = x[i+4];
-    }
-    return res;
-}
-
-
-
-AVX2NEON_ABI
-void _mm256_maskstore_epi32 (int* mem_addr, __m256i mask, __m256i a)
-{
-    _mm_maskstore_epi32(mem_addr,mask.lo,a.lo);
-    _mm_maskstore_epi32(mem_addr + 4,mask.hi,a.hi);
-}
-
-AVX2NEON_ABI
-__m256i _mm256_slli_epi32 (__m256i a, int imm8)
-{
-    __m256i res;
-    res.lo = _mm_slli_epi32(a.lo,imm8);
-    res.hi = _mm_slli_epi32(a.hi,imm8);
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_srli_epi32 (__m256i a, int imm8)
-{
-    __m256i res;
-    res.lo = _mm_srli_epi32(a.lo,imm8);
-    res.hi = _mm_srli_epi32(a.hi,imm8);
-    return res;
-}
-
-AVX2NEON_ABI
-__m256i _mm256_srai_epi32 (__m256i a, int imm8)
-{
-    __m256i res;
-    res.lo = _mm_srai_epi32(a.lo,imm8);
-    res.hi = _mm_srai_epi32(a.hi,imm8);
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_sllv_epi32 (__m256i a, __m256i count)
-{
-    __m256i res;
-    res.lo = vshlq_s32(a.lo,count.lo);
-    res.hi = vshlq_s32(a.hi,count.hi);
-    return res;
-
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_srav_epi32 (__m256i a, __m256i count)
-{
-    __m256i res;
-    res.lo = vshlq_s32(a.lo,vnegq_s32(count.lo));
-    res.hi = vshlq_s32(a.hi,vnegq_s32(count.hi));
-    return res;
-
-}
-
-AVX2NEON_ABI
-__m256i _mm256_srlv_epi32 (__m256i a, __m256i count)
-{
-    __m256i res;
-    res.lo = __m128i(vshlq_u32(uint32x4_t(a.lo),vnegq_s32(count.lo)));
-    res.hi = __m128i(vshlq_u32(uint32x4_t(a.hi),vnegq_s32(count.hi)));
-    return res;
-
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_permute2f128_si256 (__m256i a, __m256i b, int imm8)
-{
-    return __m256i(_mm256_permute2f128_ps(__m256(a),__m256(b),imm8));
-}
-
-
-AVX2NEON_ABI
-__m128i _mm256_extractf128_si256 (__m256i a, const int imm8)
-{
-    if (imm8 & 1) return a.hi;
-    return a.lo;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_set1_ps(float x)
-{
-    __m256 res;
-    res.lo = res.hi = vdupq_n_f32(x);
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_set_ps (float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0)
-{
-    __m256 res;
-    res.lo = _mm_set_ps(e3,e2,e1,e0);
-    res.hi = _mm_set_ps(e7,e6,e5,e4);
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_broadcast_ps (__m128 const * mem_addr)
-{
-    __m256 res;
-    res.lo = res.hi = *mem_addr;
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_cvtepi32_ps (__m256i a)
-{
-    __m256 res;
-    res.lo = _mm_cvtepi32_ps(a.lo);
-    res.hi = _mm_cvtepi32_ps(a.hi);
-    return res;
-}
-AVX2NEON_ABI
-void _mm256_maskstore_ps (float * mem_addr, __m256i mask, __m256 a)
-{
-    for (int i=0;i<4;i++) {
-        if (mask.lo[i] & 0x80000000) mem_addr[i] = a.lo[i];
-        if (mask.hi[i] & 0x80000000) mem_addr[i+4] = a.hi[i];
-    }
-}
-
-AVX2NEON_ABI
-__m256d _mm256_andnot_pd (__m256d a, __m256d b)
-{
-    __m256d res;
-    res.lo = float64x2_t(_mm_andnot_ps(__m128(a.lo),__m128(b.lo)));
-    res.hi = float64x2_t(_mm_andnot_ps(__m128(a.hi),__m128(b.hi)));
-    return res;
-}
-
-AVX2NEON_ABI
-__m256 _mm256_blend_ps (__m256 a, __m256 b, const int imm8)
-{
-    __m256 res;
-    res.lo = _mm_blend_ps(a.lo,b.lo,imm8 & 0xf);
-    res.hi = _mm_blend_ps(a.hi,b.hi,imm8 >> 4);
-    return res;
-
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_blend_epi32 (__m256i a, __m256i b, const int imm8)
-{
-    __m256i res;
-    res.lo = _mm_blend_epi32(a.lo,b.lo,imm8 & 0xf);
-    res.hi = _mm_blend_epi32(a.hi,b.hi,imm8 >> 4);
-    return res;
-
-}
-
-AVX2NEON_ABI
-__m256i _mm256_i32gather_epi32 (int const* base_addr, __m256i vindex, const int scale)
-{
-    __m256i res;
-    for (int i=0;i<4;i++)
-    {
-        res.lo[i] = *(int *)((char *) base_addr + (vindex.lo[i]*scale));
-        res.hi[i] = *(int *)((char *) base_addr + (vindex.hi[i]*scale));
-    }
-    return res;
-}
-
-
-AVX2NEON_ABI
-__m256i _mm256_mask_i32gather_epi32 (__m256i src, int const* base_addr, __m256i vindex, __m256i mask, const int scale)
-{
-    __m256i res = _mm256_setzero_si256();
-    for (int i=0;i<4;i++)
-    {
-        if (mask.lo[i] >> 31) res.lo[i] = *(int *)((char *) base_addr + (vindex.lo[i]*scale));
-        if (mask.hi[i] >> 31) res.hi[i] = *(int *)((char *) base_addr + (vindex.hi[i]*scale));
-    }
-    
-    return res;
-
-}
-
-

+ 0 - 1753
thirdparty/embree-aarch64/common/math/SSE2NEON.h

@@ -1,1753 +0,0 @@
-#ifndef SSE2NEON_H
-#define SSE2NEON_H
-
-// This header file provides a simple API translation layer
-// between SSE intrinsics to their corresponding ARM NEON versions
-//
-// This header file does not (yet) translate *all* of the SSE intrinsics.
-// Since this is in support of a specific porting effort, I have only
-// included the intrinsics I needed to get my port to work.
-//
-// Questions/Comments/Feedback send to: [email protected]
-//
-// If you want to improve or add to this project, send me an
-// email and I will probably approve your access to the depot.
-//
-// Project is located here:
-//
-//	https://github.com/jratcliff63367/sse2neon
-//
-// Show your appreciation for open source by sending me a bitcoin tip to the following
-// address.
-//
-// TipJar: 1PzgWDSyq4pmdAXRH8SPUtta4SWGrt4B1p :
-// https://blockchain.info/address/1PzgWDSyq4pmdAXRH8SPUtta4SWGrt4B1p
-//
-//
-// Contributors to this project are:
-//
-// John W. Ratcliff : [email protected]
-// Brandon Rowlett  : [email protected]
-// Ken Fast         : [email protected]
-// Eric van Beurden : [email protected]
-//
-//
-// *********************************************************************************************************************
-// Release notes for January 20, 2017 version:
-//
-// The unit tests have been refactored.  They no longer assert on an error, instead they return a pass/fail condition
-// The unit-tests now test 10,000 random float and int values against each intrinsic.
-//
-// SSE2NEON now supports 95 SSE intrinsics.  39 of them have formal unit tests which have been implemented and
-// fully tested on NEON/ARM.  The remaining 56 still need unit tests implemented.
-//
-// A struct is now defined in this header file called 'SIMDVec' which can be used by applications which
-// attempt to access the contents of an _m128 struct directly.  It is important to note that accessing the __m128
-// struct directly is bad coding practice by Microsoft: @see: https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx
-//
-// However, some legacy source code may try to access the contents of an __m128 struct directly so the developer
-// can use the SIMDVec as an alias for it.  Any casting must be done manually by the developer, as you cannot
-// cast or otherwise alias the base NEON data type for intrinsic operations.
-//
-// A bug was found with the _mm_shuffle_ps intrinsic.  If the shuffle permutation was not one of the ones with
-// a custom/unique implementation causing it to fall through to the default shuffle implementation it was failing
-// to return the correct value.  This is now fixed.
-//
-// A bug was found with the _mm_cvtps_epi32 intrinsic.  This converts floating point values to integers.
-// It was not honoring the correct rounding mode.  In SSE the default rounding mode when converting from float to int
-// is to use 'round to even' otherwise known as 'bankers rounding'.  ARMv7 did not support this feature but ARMv8 does.
-// As it stands today, this header file assumes ARMv8.  If you are trying to target really old ARM devices, you may get
-// a build error.
-//
-// Support for a number of new intrinsics was added, however, none of them yet have unit-tests to 100% confirm they are
-// producing the correct results on NEON.  These unit tests will be added as soon as possible.
-//
-// Here is the list of new instrinsics which have been added:
-//
-// _mm_cvtss_f32     :  extracts the lower order floating point value from the parameter
-// _mm_add_ss        : adds the scalar single - precision floating point values of a and b
-// _mm_div_ps        : Divides the four single - precision, floating - point values of a and b.
-// _mm_div_ss        : Divides the scalar single - precision floating point value of a by b.
-// _mm_sqrt_ss       : Computes the approximation of the square root of the scalar single - precision floating point value of in.
-// _mm_rsqrt_ps      : Computes the approximations of the reciprocal square roots of the four single - precision floating point values of in.
-// _mm_comilt_ss     : Compares the lower single - precision floating point scalar values of a and b using a less than operation
-// _mm_comigt_ss     : Compares the lower single - precision floating point scalar values of a and b using a greater than operation.
-// _mm_comile_ss     :  Compares the lower single - precision floating point scalar values of a and b using a less than or equal operation.
-// _mm_comige_ss     : Compares the lower single - precision floating point scalar values of a and b using a greater than or equal operation.
-// _mm_comieq_ss     :  Compares the lower single - precision floating point scalar values of a and b using an equality operation.
-// _mm_comineq_s     :  Compares the lower single - precision floating point scalar values of a and b using an inequality operation
-// _mm_unpackhi_epi8 : Interleaves the upper 8 signed or unsigned 8 - bit integers in a with the upper 8 signed or unsigned 8 - bit integers in b.
-// _mm_unpackhi_epi16:  Interleaves the upper 4 signed or unsigned 16 - bit integers in a with the upper 4 signed or unsigned 16 - bit integers in b.
-//
-// *********************************************************************************************************************
-/*
-** The MIT license:
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is furnished
-** to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in all
-** copies or substantial portions of the Software.
-
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#pragma once
-
-#define GCC 1
-#define ENABLE_CPP_VERSION 0
-
-// enable precise emulation of _mm_min_ps and _mm_max_ps?
-// This would slow down the computation a bit, but gives consistent result with x86 SSE2.
-// (e.g. would solve a hole or NaN pixel in the rendering result)
-#define USE_PRECISE_MINMAX_IMPLEMENTATION (1)
-
-#if GCC
-#define FORCE_INLINE					inline __attribute__((always_inline))
-#define ALIGN_STRUCT(x)					__attribute__((aligned(x)))
-#else
-#define FORCE_INLINE					inline
-#define ALIGN_STRUCT(x)					__declspec(align(x))
-#endif
-
-#include <stdint.h>
-#include "arm_neon.h"
-#if defined(__aarch64__)
-#include "constants.h"
-#endif
-
-
-#if !defined(__has_builtin)
-#define __has_builtin(x) (0)
-#endif
-
-/*******************************************************/
-/* MACRO for shuffle parameter for _mm_shuffle_ps().   */
-/* Argument fp3 is a digit[0123] that represents the fp*/
-/* from argument "b" of mm_shuffle_ps that will be     */
-/* placed in fp3 of result. fp2 is the same for fp2 in */
-/* result. fp1 is a digit[0123] that represents the fp */
-/* from argument "a" of mm_shuffle_ps that will be     */
-/* places in fp1 of result. fp0 is the same for fp0 of */
-/* result                                              */
-/*******************************************************/
-#if defined(__aarch64__)
-#define _MN_SHUFFLE(fp3,fp2,fp1,fp0) ( (uint8x16_t){ (((fp3)*4)+0), (((fp3)*4)+1), (((fp3)*4)+2), (((fp3)*4)+3),  (((fp2)*4)+0), (((fp2)*4)+1), (((fp2)*4)+2), (((fp2)*4)+3),  (((fp1)*4)+0), (((fp1)*4)+1), (((fp1)*4)+2), (((fp1)*4)+3),  (((fp0)*4)+0), (((fp0)*4)+1), (((fp0)*4)+2), (((fp0)*4)+3) } )
-#define _MF_SHUFFLE(fp3,fp2,fp1,fp0) ( (uint8x16_t){ (((fp3)*4)+0), (((fp3)*4)+1), (((fp3)*4)+2), (((fp3)*4)+3),  (((fp2)*4)+0), (((fp2)*4)+1), (((fp2)*4)+2), (((fp2)*4)+3),  (((fp1)*4)+16+0), (((fp1)*4)+16+1), (((fp1)*4)+16+2), (((fp1)*4)+16+3),  (((fp0)*4)+16+0), (((fp0)*4)+16+1), (((fp0)*4)+16+2), (((fp0)*4)+16+3) } )
-#endif
-
-#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) (((fp3) << 6) | ((fp2) << 4) | \
-  ((fp1) << 2) | ((fp0)))
-
-typedef float32x4_t __m128;
-typedef int32x4_t __m128i;
-
-// union intended to allow direct access to an __m128 variable using the names that the MSVC
-// compiler provides.  This union should really only be used when trying to access the members
-// of the vector as integer values.  GCC/clang allow native access to the float members through
-// a simple array access operator (in C since 4.6, in C++ since 4.8).
-//
-// Ideally direct accesses to SIMD vectors should not be used since it can cause a performance
-// hit.  If it really is needed however, the original __m128 variable can be aliased with a
-// pointer to this union and used to access individual components.  The use of this union should
-// be hidden behind a macro that is used throughout the codebase to access the members instead
-// of always declaring this type of variable.
-typedef union ALIGN_STRUCT(16) SIMDVec
-{
-  float       m128_f32[4];    // as floats - do not to use this.  Added for convenience.
-  int8_t      m128_i8[16];    // as signed 8-bit integers.
-  int16_t     m128_i16[8];    // as signed 16-bit integers.
-  int32_t     m128_i32[4];    // as signed 32-bit integers.
-  int64_t     m128_i64[2];    // as signed 64-bit integers.
-  uint8_t     m128_u8[16];    // as unsigned 8-bit integers.
-  uint16_t    m128_u16[8];    // as unsigned 16-bit integers.
-  uint32_t    m128_u32[4];    // as unsigned 32-bit integers.
-  uint64_t    m128_u64[2];    // as unsigned 64-bit integers.
-  double	    m128_f64[2];    // as signed double
-} SIMDVec;
-
-// ******************************************
-// CPU stuff
-// ******************************************
-
-typedef SIMDVec __m128d;
-
-#include <stdlib.h>
-
-#ifndef _MM_MASK_MASK
-#define _MM_MASK_MASK 0x1f80
-#define _MM_MASK_DIV_ZERO 0x200
-#define _MM_FLUSH_ZERO_ON 0x8000
-#define _MM_DENORMALS_ZERO_ON 0x40
-#define _MM_MASK_DENORM 0x100
-#endif
-#define _MM_SET_EXCEPTION_MASK(x)
-#define _MM_SET_FLUSH_ZERO_MODE(x)
-#define _MM_SET_DENORMALS_ZERO_MODE(x)
-
-FORCE_INLINE void _mm_pause()
-{
-}
-
-FORCE_INLINE void _mm_mfence()
-{
-    __sync_synchronize();
-}
-
-#define _MM_HINT_T0 3
-#define _MM_HINT_T1 2
-#define _MM_HINT_T2 1
-#define _MM_HINT_NTA 0
-
-FORCE_INLINE void _mm_prefetch(const void* ptr, unsigned int level)
-{
-   __builtin_prefetch(ptr);
- 
-}
-
-FORCE_INLINE void* _mm_malloc(int size, int align)
-{
-    void *ptr;
-    // align must be multiple of sizeof(void *) for posix_memalign.
-    if (align < sizeof(void *)) {
-        align = sizeof(void *);
-    }
-
-    if ((align % sizeof(void *)) != 0) {
-        // fallback to malloc
-        ptr = malloc(size);
-    } else {
-        if (posix_memalign(&ptr, align, size)) {
-          return 0;
-        }
-    }
-
-    return ptr;
-}
-
-FORCE_INLINE void _mm_free(void* ptr)
-{
-        free(ptr);
-}
-
-FORCE_INLINE int _mm_getcsr()
-{
-        return 0;
-}
-
-FORCE_INLINE void _mm_setcsr(int val)
-{
-        return;
-}
-
-// ******************************************
-// Set/get methods
-// ******************************************
-
-// extracts the lower order floating point value from the parameter : https://msdn.microsoft.com/en-us/library/bb514059%28v=vs.120%29.aspx?f=255&MSPPError=-2147217396
-#if defined(__aarch64__)
-FORCE_INLINE float _mm_cvtss_f32(const __m128& x)
-{
-    return x[0];
-}
-#else
-FORCE_INLINE float _mm_cvtss_f32(__m128 a)
-{
-    return vgetq_lane_f32(a, 0);
-}
-#endif
-
-// Sets the 128-bit value to zero https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_setzero_si128()
-{
-  return vdupq_n_s32(0);
-}
-
-// Clears the four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_setzero_ps(void)
-{
-  return vdupq_n_f32(0);
-}
-
-// Sets the four single-precision, floating-point values to w. https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_set1_ps(float _w)
-{
-  return vdupq_n_f32(_w);
-}
-
-// Sets the four single-precision, floating-point values to w. https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_set_ps1(float _w)
-{
-  return vdupq_n_f32(_w);
-}
-
-// Sets the four single-precision, floating-point values to the four inputs. https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx
-#if defined(__aarch64__) 
-FORCE_INLINE __m128 _mm_set_ps(const float w, const float z, const float y, const float x)
-{
-    float32x4_t t = { x, y, z, w };
-    return t;
-}
-
-// Sets the four single-precision, floating-point values to the four inputs in reverse order. https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_setr_ps(const float w, const float z , const float y , const float x )
-{
-    float32x4_t t = { w, z, y, x };
-    return t;
-}
-#else
-FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x)
-{
-    float __attribute__((aligned(16))) data[4] = { x, y, z, w };
-    return vld1q_f32(data);
-}
-
-// Sets the four single-precision, floating-point values to the four inputs in reverse order. https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_setr_ps(float w, float z , float y , float x )
-{
-    float __attribute__ ((aligned (16))) data[4] = { w, z, y, x };
-    return vld1q_f32(data);
-}
-#endif
-
-// Sets the 4 signed 32-bit integer values to i. https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_set1_epi32(int _i)
-{
-  return vdupq_n_s32(_i);
-}
-
-//Set the first lane to of 4 signed single-position, floating-point number to w
-#if defined(__aarch64__)
-FORCE_INLINE __m128 _mm_set_ss(float _w)
-{
-    float32x4_t res = {_w, 0, 0, 0};
-    return res;
-}
-
-// Sets the 4 signed 32-bit integer values. https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
-{
-    int32x4_t t = {i0,i1,i2,i3};
-    return t;
-}
-#else
-FORCE_INLINE __m128 _mm_set_ss(float _w)
-{
-    __m128 val = _mm_setzero_ps();
-    return vsetq_lane_f32(_w, val, 0);
-}
-
-// Sets the 4 signed 32-bit integer values. https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
-{
-    int32_t __attribute__((aligned(16))) data[4] = { i0, i1, i2, i3 };
-    return vld1q_s32(data);
-}
-#endif
-
-// Stores four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx
-FORCE_INLINE void _mm_store_ps(float *p, __m128 a)
-{
-  vst1q_f32(p, a);
-}
-
-// Stores four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx
-FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a)
-{
-  vst1q_f32(p, a);
-}
-
-FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a)
-{
-  vst1q_s32((int32_t*) p,a);
-}
-
-// Stores four 32-bit integer values as (as a __m128i value) at the address p. https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
-FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a )
-{
-  vst1q_s32((int32_t*) p,a);
-}
-
-// Stores the lower single - precision, floating - point value. https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx
-FORCE_INLINE void _mm_store_ss(float *p, __m128 a)
-{
-  vst1q_lane_f32(p, a, 0);
-}
-
-// Reads the lower 64 bits of b and stores them into the lower 64 bits of a.  https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx
-FORCE_INLINE void _mm_storel_epi64(__m128i* a, __m128i b)
-{
-  *a = (__m128i)vsetq_lane_s64((int64_t)vget_low_s32(b), *(int64x2_t*)a, 0);
-}
-
-// Loads a single single-precision, floating-point value, copying it into all four words https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_load1_ps(const float * p)
-{
-  return vld1q_dup_f32(p);
-}
-
-// Loads four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_load_ps(const float * p)
-{
-  return vld1q_f32(p);
-}
-
-// Loads four single-precision, floating-point values.  https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx
-FORCE_INLINE __m128 _mm_loadu_ps(const float * p)
-{
-  // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are equivalent for neon
-  return vld1q_f32(p);
-}
-
-// Loads an single - precision, floating - point value into the low word and clears the upper three words.  https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx
-FORCE_INLINE __m128 _mm_load_ss(const float * p)
-{
-  __m128 result = vdupq_n_f32(0);
-  return vsetq_lane_f32(*p, result, 0);
-}
-
-FORCE_INLINE __m128i _mm_loadu_si128(__m128i *p)
-{
-  return (__m128i)vld1q_s32((const int32_t*) p);
-}
-
-
-// ******************************************
-// Logic/Binary operations
-// ******************************************
-
-// Compares for inequality.  https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b)
-{
-  return (__m128)vmvnq_s32((__m128i)vceqq_f32(a, b));
-}
-
-// Computes the bitwise AND-NOT of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b)
-{
-  return (__m128)vbicq_s32((__m128i)b, (__m128i)a); // *NOTE* argument swap
-}
-
-// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the 128-bit value in a. https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b)
-{
-  return (__m128i)vbicq_s32(b, a); // *NOTE* argument swap
-}
-
-// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in b. https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b)
-{
-  return (__m128i)vandq_s32(a, b);
-}
-
-// Computes the bitwise AND of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b)
-{
-  return (__m128)vandq_s32((__m128i)a, (__m128i)b);
-}
-
-// Computes the bitwise OR of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)
-{
-  return (__m128)vorrq_s32((__m128i)a, (__m128i)b);
-}
-
-// Computes bitwise EXOR (exclusive-or) of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b)
-{
-  return (__m128)veorq_s32((__m128i)a, (__m128i)b);
-}
-
-// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b)
-{
-  return (__m128i)vorrq_s32(a, b);
-}
-
-// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in b.  https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b)
-{
-  return veorq_s32(a, b);
-}
-
-// NEON does not provide this method
-// Creates a 4-bit mask from the most significant bits of the four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx
-FORCE_INLINE int _mm_movemask_ps(__m128 a)
-{
-#if ENABLE_CPP_VERSION // I am not yet convinced that the NEON version is faster than the C version of this
-  uint32x4_t &ia = *(uint32x4_t *)&a;
-  return (ia[0] >> 31) | ((ia[1] >> 30) & 2) | ((ia[2] >> 29) & 4) | ((ia[3] >> 28) & 8);
-#else
-    
-#if defined(__aarch64__)
-    uint32x4_t t2 = vandq_u32(vreinterpretq_u32_f32(a), embree::movemask_mask);
-    return vaddvq_u32(t2);
-#else
-  static const uint32x4_t movemask = { 1, 2, 4, 8 };
-  static const uint32x4_t highbit = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
-  uint32x4_t t0 = vreinterpretq_u32_f32(a);
-  uint32x4_t t1 = vtstq_u32(t0, highbit);
-  uint32x4_t t2 = vandq_u32(t1, movemask);
-  uint32x2_t t3 = vorr_u32(vget_low_u32(t2), vget_high_u32(t2));
-  return vget_lane_u32(t3, 0) | vget_lane_u32(t3, 1);
-#endif
-    
-#endif
-}
-
-#if defined(__aarch64__)
-FORCE_INLINE int _mm_movemask_popcnt_ps(__m128 a)
-{
-    uint32x4_t t2 = vandq_u32(vreinterpretq_u32_f32(a), embree::movemask_mask);
-    t2 = vreinterpretq_u32_u8(vcntq_u8(vreinterpretq_u8_u32(t2)));
-    return vaddvq_u32(t2);
-    
-}
-#endif
-
-// Takes the upper 64 bits of a and places it in the low end of the result
-// Takes the lower 64 bits of b and places it into the high end of the result.
-FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b)
-{
-  return vcombine_f32(vget_high_f32(a), vget_low_f32(b));
-}
-
-// takes the lower two 32-bit values from a and swaps them and places in high end of result
-// takes the higher two 32 bit values from b and swaps them and places in low end of result.
-FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b)
-{
-  return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(b)));
-}
-
-// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the high
-FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b)
-{
-  return vcombine_f32(vget_low_f32(a), vget_high_f32(b));
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b)
-{
-  return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 1)), vdup_n_f32(vgetq_lane_f32(b, 0)));
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b)
-{
-  return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 2)), vdup_n_f32(vgetq_lane_f32(b, 0)));
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b)
-{
-  return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 0)), vdup_n_f32(vgetq_lane_f32(b, 2)));
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b)
-{
-  float32_t a0 = vgetq_lane_f32(a, 0);
-  float32_t a2 = vgetq_lane_f32(a, 2);
-  float32x2_t aVal = vdup_n_f32(a2);
-  aVal = vset_lane_f32(a0, aVal, 1);
-  return vcombine_f32(aVal, vget_high_f32(b));
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b)
-{
-  return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 3)), vdup_n_f32(vgetq_lane_f32(b, 1)));
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b)
-{
-  float32_t b0 = vgetq_lane_f32(b, 0);
-  float32_t b2 = vgetq_lane_f32(b, 2);
-  float32x2_t bVal = vdup_n_f32(b0);
-  bVal = vset_lane_f32(b2, bVal, 1);
-  return vcombine_f32(vget_low_f32(a), bVal);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b)
-{
-  float32_t b0 = vgetq_lane_f32(b, 0);
-  float32_t b2 = vgetq_lane_f32(b, 2);
-  float32x2_t bVal = vdup_n_f32(b0);
-  bVal = vset_lane_f32(b2, bVal, 1);
-  return vcombine_f32(vrev64_f32(vget_low_f32(a)), bVal);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b)
-{
-  float32_t b0 = vgetq_lane_f32(b, 0);
-  float32_t b2 = vgetq_lane_f32(b, 2);
-  float32x2_t bVal = vdup_n_f32(b0);
-  bVal = vset_lane_f32(b2, bVal, 1);
-  return vcombine_f32(vget_high_f32(a), bVal);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b)
-{
-  float32x2_t a21 = vget_high_f32(vextq_f32(a, a, 3));
-  float32x2_t b03 = vget_low_f32(vextq_f32(b, b, 3));
-  return vcombine_f32(a21, b03);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b)
-{
-  float32x2_t a03 = vget_low_f32(vextq_f32(a, a, 3));
-  float32x2_t b21 = vget_high_f32(vextq_f32(b, b, 3));
-  return vcombine_f32(a03, b21);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b)
-{
-  float32x2_t a10 = vget_low_f32(a);
-  float32x2_t b10 = vget_low_f32(b);
-  return vcombine_f32(a10, b10);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b)
-{
-  float32x2_t a01 = vrev64_f32(vget_low_f32(a));
-  float32x2_t b10 = vget_low_f32(b);
-  return vcombine_f32(a01, b10);
-}
-
-FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b)
-{
-  float32x2_t a01 = vrev64_f32(vget_low_f32(a));
-  float32x2_t b01 = vrev64_f32(vget_low_f32(b));
-  return vcombine_f32(a01, b01);
-}
-
-// NEON does not support a general purpose permute intrinsic
-// Currently I am not sure whether the C implementation is faster or slower than the NEON version.
-// Note, this has to be expanded as a template because the shuffle value must be an immediate value.
-// The same is true on SSE as well.
-// Selects four specific single-precision, floating-point values from a and b, based on the mask i. https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx
-template <int i>
-FORCE_INLINE __m128 _mm_shuffle_ps_default(const __m128& a, const __m128& b)
-{
-#if ENABLE_CPP_VERSION // I am not convinced that the NEON version is faster than the C version yet.
-  __m128 ret;
-  ret[0] = a[i & 0x3];
-  ret[1] = a[(i >> 2) & 0x3];
-  ret[2] = b[(i >> 4) & 0x03];
-  ret[3] = b[(i >> 6) & 0x03];
-  return ret;
-#else
-# if __has_builtin(__builtin_shufflevector)
-    return __builtin_shufflevector(             \
-        a, b, (i) & (0x3), ((i) >> 2) & 0x3,
-        (((i) >> 4) & 0x3) + 4, (((i) >> 6) & 0x3) + 4);
-# else
-    const int i0 = (i >> 0)&0x3;
-    const int i1 = (i >> 2)&0x3;
-    const int i2 = (i >> 4)&0x3;
-    const int i3 = (i >> 6)&0x3;
-
-    if (&a == &b)
-     {
-         if (i0 == i1 && i0 == i2 && i0 == i3)
-         {
-             return (float32x4_t)vdupq_laneq_f32(a,i0);
-         }
-         static const uint8_t tbl[16] = {
-             (i0*4) + 0,(i0*4) + 1,(i0*4) + 2,(i0*4) + 3,
-             (i1*4) + 0,(i1*4) + 1,(i1*4) + 2,(i1*4) + 3,
-             (i2*4) + 0,(i2*4) + 1,(i2*4) + 2,(i2*4) + 3,
-             (i3*4) + 0,(i3*4) + 1,(i3*4) + 2,(i3*4) + 3
-         };
-         
-         return (float32x4_t)vqtbl1q_s8(int8x16_t(b),*(uint8x16_t *)tbl);
-         
-     }
-     else
-     {
-         
-         static const uint8_t tbl[16] = {
-             (i0*4) + 0,(i0*4) + 1,(i0*4) + 2,(i0*4) + 3,
-             (i1*4) + 0,(i1*4) + 1,(i1*4) + 2,(i1*4) + 3,
-             (i2*4) + 0 + 16,(i2*4) + 1 + 16,(i2*4) + 2 + 16,(i2*4) + 3 + 16,
-             (i3*4) + 0 + 16,(i3*4) + 1 + 16,(i3*4) + 2 + 16,(i3*4) + 3 + 16
-         };
-         
-         return float32x4_t(vqtbl2q_s8((int8x16x2_t){int8x16_t(a),int8x16_t(b)},*(uint8x16_t *)tbl));
-     }
-# endif //builtin(shufflevector)
-#endif
-}
-
-template <int i >
-FORCE_INLINE __m128 _mm_shuffle_ps_function(const __m128& a, const __m128& b)
-{
-  switch (i)
-  {
-    case _MM_SHUFFLE(1, 0, 3, 2):
-      return _mm_shuffle_ps_1032(a, b);
-      break;
-    case _MM_SHUFFLE(2, 3, 0, 1):
-      return _mm_shuffle_ps_2301(a, b);
-      break;
-    case _MM_SHUFFLE(3, 2, 1, 0):
-      return _mm_shuffle_ps_3210(a, b);
-      break;
-    case _MM_SHUFFLE(0, 0, 1, 1):
-      return _mm_shuffle_ps_0011(a, b);
-      break;
-    case _MM_SHUFFLE(0, 0, 2, 2):
-      return _mm_shuffle_ps_0022(a, b);
-      break;
-    case _MM_SHUFFLE(2, 2, 0, 0):
-      return _mm_shuffle_ps_2200(a, b);
-      break;
-    case _MM_SHUFFLE(3, 2, 0, 2):
-      return _mm_shuffle_ps_3202(a, b);
-      break;
-    case _MM_SHUFFLE(1, 1, 3, 3):
-      return _mm_shuffle_ps_1133(a, b);
-      break;
-    case _MM_SHUFFLE(2, 0, 1, 0):
-      return _mm_shuffle_ps_2010(a, b);
-      break;
-    case _MM_SHUFFLE(2, 0, 0, 1):
-      return _mm_shuffle_ps_2001(a, b);
-      break;
-    case _MM_SHUFFLE(2, 0, 3, 2):
-      return _mm_shuffle_ps_2032(a, b);
-      break;
-    case _MM_SHUFFLE(0, 3, 2, 1):
-      return _mm_shuffle_ps_0321(a, b);
-      break;
-    case _MM_SHUFFLE(2, 1, 0, 3):
-      return _mm_shuffle_ps_2103(a, b);
-      break;
-    case _MM_SHUFFLE(1, 0, 1, 0):
-      return _mm_shuffle_ps_1010(a, b);
-      break;
-    case _MM_SHUFFLE(1, 0, 0, 1):
-      return _mm_shuffle_ps_1001(a, b);
-      break;
-    case _MM_SHUFFLE(0, 1, 0, 1):
-      return _mm_shuffle_ps_0101(a, b);
-      break;
-  }
-  return _mm_shuffle_ps_default<i>(a, b);
-}
-
-# if __has_builtin(__builtin_shufflevector)
-#define _mm_shuffle_ps(a,b,i) _mm_shuffle_ps_default<i>(a,b)
-# else
-#define _mm_shuffle_ps(a,b,i) _mm_shuffle_ps_function<i>(a,b)
-#endif
-
-// Takes the upper 64 bits of a and places it in the low end of the result
-// Takes the lower 64 bits of b and places it into the high end of the result.
-FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a, __m128i b)
-{
-  return vcombine_s32(vget_high_s32(a), vget_low_s32(b));
-}
-
-// takes the lower two 32-bit values from a and swaps them and places in low end of result
-// takes the higher two 32 bit values from b and swaps them and places in high end of result.
-FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a, __m128i b)
-{
-  return vcombine_s32(vrev64_s32(vget_low_s32(a)), vrev64_s32(vget_high_s32(b)));
-}
-
-// shift a right by 32 bits, and put the lower 32 bits of a into the upper 32 bits of b
-// when a and b are the same, rotates the least significant 32 bits into the most signficant 32 bits, and shifts the rest down
-FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a, __m128i b)
-{
-  return vextq_s32(a, b, 1);
-}
-
-// shift a left by 32 bits, and put the upper 32 bits of b into the lower 32 bits of a
-// when a and b are the same, rotates the most significant 32 bits into the least signficant 32 bits, and shifts the rest up
-FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a, __m128i b)
-{
-  return vextq_s32(a, b, 3);
-}
-
-// gets the lower 64 bits of a, and places it in the upper 64 bits
-// gets the lower 64 bits of b and places it in the lower 64 bits
-FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a, __m128i b)
-{
-  return vcombine_s32(vget_low_s32(a), vget_low_s32(a));
-}
-
-// gets the lower 64 bits of a, and places it in the upper 64 bits
-// gets the lower 64 bits of b, swaps the 0 and 1 elements, and places it in the lower 64 bits
-FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a, __m128i b)
-{
-  return vcombine_s32(vrev64_s32(vget_low_s32(a)), vget_low_s32(b));
-}
-
-// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the upper 64 bits
-// gets the lower 64 bits of b, swaps the 0 and 1 elements, and places it in the lower 64 bits
-FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a, __m128i b)
-{
-  return vcombine_s32(vrev64_s32(vget_low_s32(a)), vrev64_s32(vget_low_s32(b)));
-}
-
-FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a, __m128i b)
-{
-  return vcombine_s32(vdup_n_s32(vgetq_lane_s32(a, 1)), vdup_n_s32(vgetq_lane_s32(b, 2)));
-}
-
-FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a, __m128i b)
-{
-  return vcombine_s32(vdup_n_s32(vgetq_lane_s32(a, 2)), vrev64_s32(vget_low_s32(b)));
-}
-
-FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a, __m128i b)
-{
-  return vcombine_s32(vget_high_s32(a), vdup_n_s32(vgetq_lane_s32(b, 3)));
-}
-
-template <int i >
-FORCE_INLINE __m128i _mm_shuffle_epi32_default(__m128i a, __m128i b)
-{
-#if ENABLE_CPP_VERSION
-  __m128i ret;
-  ret[0] = a[i & 0x3];
-  ret[1] = a[(i >> 2) & 0x3];
-  ret[2] = b[(i >> 4) & 0x03];
-  ret[3] = b[(i >> 6) & 0x03];
-  return ret;
-#else
-  __m128i ret = vmovq_n_s32(vgetq_lane_s32(a, i & 0x3));
-  ret = vsetq_lane_s32(vgetq_lane_s32(a, (i >> 2) & 0x3), ret, 1);
-  ret = vsetq_lane_s32(vgetq_lane_s32(b, (i >> 4) & 0x3), ret, 2);
-  ret = vsetq_lane_s32(vgetq_lane_s32(b, (i >> 6) & 0x3), ret, 3);
-  return ret;
-#endif
-}
-
-template <int i >
-FORCE_INLINE __m128i _mm_shuffle_epi32_function(__m128i a, __m128i b)
-{
-  switch (i)
-  {
-    case _MM_SHUFFLE(1, 0, 3, 2): return _mm_shuffle_epi_1032(a, b); break;
-    case _MM_SHUFFLE(2, 3, 0, 1): return _mm_shuffle_epi_2301(a, b); break;
-    case _MM_SHUFFLE(0, 3, 2, 1): return _mm_shuffle_epi_0321(a, b); break;
-    case _MM_SHUFFLE(2, 1, 0, 3): return _mm_shuffle_epi_2103(a, b); break;
-    case _MM_SHUFFLE(1, 0, 1, 0): return _mm_shuffle_epi_1010(a, b); break;
-    case _MM_SHUFFLE(1, 0, 0, 1): return _mm_shuffle_epi_1001(a, b); break;
-    case _MM_SHUFFLE(0, 1, 0, 1): return _mm_shuffle_epi_0101(a, b); break;
-    case _MM_SHUFFLE(2, 2, 1, 1): return _mm_shuffle_epi_2211(a, b); break;
-    case _MM_SHUFFLE(0, 1, 2, 2): return _mm_shuffle_epi_0122(a, b); break;
-    case _MM_SHUFFLE(3, 3, 3, 2): return _mm_shuffle_epi_3332(a, b); break;
-    default: return _mm_shuffle_epi32_default<i>(a, b);
-  }
-}
-
-template <int i >
-FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a)
-{
-  return vdupq_n_s32(vgetq_lane_s32(a, i));
-}
-
-template <int i>
-FORCE_INLINE __m128i _mm_shuffle_epi32_single(__m128i a)
-{
-  switch (i)
-  {
-    case _MM_SHUFFLE(0, 0, 0, 0): return _mm_shuffle_epi32_splat<0>(a); break;
-    case _MM_SHUFFLE(1, 1, 1, 1): return _mm_shuffle_epi32_splat<1>(a); break;
-    case _MM_SHUFFLE(2, 2, 2, 2): return _mm_shuffle_epi32_splat<2>(a); break;
-    case _MM_SHUFFLE(3, 3, 3, 3): return _mm_shuffle_epi32_splat<3>(a); break;
-    default: return _mm_shuffle_epi32_function<i>(a, a);
-  }
-}
-
-// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm.	https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx
-#define _mm_shuffle_epi32(a,i) _mm_shuffle_epi32_single<i>(a)
-
-template <int i>
-FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a)
-{
-  int16x8_t ret = (int16x8_t)a;
-  int16x4_t highBits = vget_high_s16(ret);
-  ret = vsetq_lane_s16(vget_lane_s16(highBits, i & 0x3), ret, 4);
-  ret = vsetq_lane_s16(vget_lane_s16(highBits, (i >> 2) & 0x3), ret, 5);
-  ret = vsetq_lane_s16(vget_lane_s16(highBits, (i >> 4) & 0x3), ret, 6);
-  ret = vsetq_lane_s16(vget_lane_s16(highBits, (i >> 6) & 0x3), ret, 7);
-  return (__m128i)ret;
-}
-
-// Shuffles the upper 4 signed or unsigned 16 - bit integers in a as specified by imm.  https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx
-#define _mm_shufflehi_epi16(a,i) _mm_shufflehi_epi16_function<i>(a)
-
-// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while shifting in zeros. : https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx
-//#define _mm_slli_epi32(a, imm) (__m128i)vshlq_n_s32(a,imm)
-
-// Based on SIMDe
-FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, const int imm8)
-{
-#if defined(__aarch64__)
-    const int32x4_t s = vdupq_n_s32(imm8);
-    return vshlq_s32(a, s);
-#else
-  int32_t __attribute__((aligned(16))) data[4];
-  vst1q_s32(data, a);
-  const int s = (imm8 > 31) ? 0 : imm8;
-  data[0] = data[0] << s;
-  data[1] = data[1] << s;
-  data[2] = data[2] << s;
-  data[3] = data[3] << s;
-
-  return vld1q_s32(data);
-#endif
-}
-
-
-//Shifts the 4 signed or unsigned 32-bit integers in a right by count bits while shifting in zeros.  https://msdn.microsoft.com/en-us/library/w486zcfa(v=vs.100).aspx
-//#define _mm_srli_epi32( a, imm ) (__m128i)vshrq_n_u32((uint32x4_t)a, imm)
-
-// Based on SIMDe
-FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, const int imm8)
-{
-#if defined(__aarch64__)
-    const int shift = (imm8 > 31) ? 0 : imm8;  // Unfortunately, we need to check for this case for embree.
-    const int32x4_t s = vdupq_n_s32(-shift);
-    return vreinterpretq_s32_u32(vshlq_u32(vreinterpretq_u32_s32(a), s));
-#else
-  int32_t __attribute__((aligned(16))) data[4];
-  vst1q_s32(data, a);
-
-  const int s = (imm8 > 31) ? 0 : imm8;
-
-  data[0] = data[0] >> s;
-  data[1] = data[1] >> s;
-  data[2] = data[2] >> s;
-  data[3] = data[3] >> s;
-
-  return vld1q_s32(data);
-#endif
-}
-
-
-// Shifts the 4 signed 32 - bit integers in a right by count bits while shifting in the sign bit.  https://msdn.microsoft.com/en-us/library/z1939387(v=vs.100).aspx
-//#define _mm_srai_epi32( a, imm ) vshrq_n_s32(a, imm)
-
-// Based on SIMDe
-FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, const int imm8)
-{
-#if defined(__aarch64__)
-    const int32x4_t s = vdupq_n_s32(-imm8);
-    return vshlq_s32(a, s);
-#else
-  int32_t __attribute__((aligned(16))) data[4];
-  vst1q_s32(data, a);
-  const uint32_t m = (uint32_t) ((~0U) << (32 - imm8));
-
-  for (int i = 0; i < 4; i++) {
-    uint32_t is_neg = ((uint32_t) (((data[i]) >> 31)));
-    data[i] = (data[i] >> imm8) | (m * is_neg);
-  }
-
-  return vld1q_s32(data);
-#endif
-}
-
-// Shifts the 128 - bit value in a right by imm bytes while shifting in zeros.imm must be an immediate. https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx
-//#define _mm_srli_si128( a, imm ) (__m128i)vmaxq_s8((int8x16_t)a, vextq_s8((int8x16_t)a, vdupq_n_s8(0), imm))
-#define _mm_srli_si128( a, imm ) (__m128i)vextq_s8((int8x16_t)a, vdupq_n_s8(0), (imm))
-
-// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm must be an immediate.  https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx
-#define _mm_slli_si128( a, imm ) (__m128i)vextq_s8(vdupq_n_s8(0), (int8x16_t)a, 16 - (imm))
-
-// NEON does not provide a version of this function, here is an article about some ways to repro the results.
-// http://stackoverflow.com/questions/11870910/sse-mm-movemask-epi8-equivalent-method-for-arm-neon
-// Creates a 16-bit mask from the most significant bits of the 16 signed or unsigned 8-bit integers in a and zero extends the upper bits. https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx
-FORCE_INLINE int _mm_movemask_epi8(__m128i _a)
-{
-  uint8x16_t input = (uint8x16_t)_a;
-  const int8_t __attribute__((aligned(16))) xr[8] = { -7, -6, -5, -4, -3, -2, -1, 0 };
-  uint8x8_t mask_and = vdup_n_u8(0x80);
-  int8x8_t mask_shift = vld1_s8(xr);
-
-  uint8x8_t lo = vget_low_u8(input);
-  uint8x8_t hi = vget_high_u8(input);
-
-  lo = vand_u8(lo, mask_and);
-  lo = vshl_u8(lo, mask_shift);
-
-  hi = vand_u8(hi, mask_and);
-  hi = vshl_u8(hi, mask_shift);
-
-  lo = vpadd_u8(lo, lo);
-  lo = vpadd_u8(lo, lo);
-  lo = vpadd_u8(lo, lo);
-
-  hi = vpadd_u8(hi, hi);
-  hi = vpadd_u8(hi, hi);
-  hi = vpadd_u8(hi, hi);
-
-  return ((hi[0] << 8) | (lo[0] & 0xFF));
-}
-
-
-// ******************************************
-// Math operations
-// ******************************************
-
-// Subtracts the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b)
-{
-  return vsubq_f32(a, b);
-}
-
-FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b)
-{
-  return vsubq_f32(a, b);
-}
-
-// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or unsigned 32-bit integers of a. https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b)
-{
-  return vsubq_s32(a, b);
-}
-
-// Adds the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b)
-{
-  return vaddq_f32(a, b);
-}
-
-// adds the scalar single-precision floating point values of a and b.  https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b)
-{
-  const float32_t     b0 = vgetq_lane_f32(b, 0);
-  float32x4_t         value = vdupq_n_f32(0);
-
-  //the upper values in the result must be the remnants of <a>.
-  value = vsetq_lane_f32(b0, value, 0);
-  return vaddq_f32(a, value);
-}
-
-// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or unsigned 32-bit integers in b. https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b)
-{
-  return vaddq_s32(a, b);
-}
-
-// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or unsigned 16-bit integers in b. https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b)
-{
-  return (__m128i)vaddq_s16((int16x8_t)a, (int16x8_t)b);
-}
-
-// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or unsigned 16-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b)
-{
-  return (__m128i)vmulq_s16((int16x8_t)a, (int16x8_t)b);
-}
-
-// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or unsigned 32-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_mullo_epi32 (__m128i a, __m128i b)
-{
-  return (__m128i)vmulq_s32((int32x4_t)a,(int32x4_t)b);
-}
-
-// Multiplies the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b)
-{
-  return vmulq_f32(a, b);
-}
-
-FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b)
-{
-  return vmulq_f32(a, b);
-}
-
-// Computes the approximations of reciprocals of the four single-precision, floating-point values of a. https://msdn.microsoft.com/en-us/library/vstudio/796k1tty(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_rcp_ps(__m128 in)
-{
-#if defined(BUILD_IOS)
-  return vdivq_f32(vdupq_n_f32(1.0f),in);
-    
-#endif
-    // Get an initial estimate of 1/in.
-  float32x4_t reciprocal = vrecpeq_f32(in);
-
-  // We only return estimated 1/in.
-  // Newton-Raphon iteration shold be done in the outside of _mm_rcp_ps().
-
-  // TODO(LTE): We could delete these ifdef?
-  reciprocal = vmulq_f32(vrecpsq_f32(in, reciprocal), reciprocal);
-  reciprocal = vmulq_f32(vrecpsq_f32(in, reciprocal), reciprocal);
-  return reciprocal;
-
-}
-
-FORCE_INLINE __m128 _mm_rcp_ss(__m128 in)
-{
-  float32x4_t value;
-  float32x4_t result = in;
-
-  value = _mm_rcp_ps(in);
-  return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
-}
-
-// Divides the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b)
-{
-#if defined(BUILD_IOS) 
-  return vdivq_f32(a,b);
-#else
-  float32x4_t reciprocal = _mm_rcp_ps(b);
-    
-  reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
-  reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
-
-  // Add one more round of newton-raphson since NEON's reciprocal estimation has less accuracy compared to SSE2's rcp.
-  reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
-
-  // Another round for safety
-  reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
-
-    
-  return vmulq_f32(a, reciprocal);
-#endif
-}
-
-// Divides the scalar single-precision floating point value of a by b.  https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b)
-{
-  float32x4_t value;
-  float32x4_t result = a;
-  value = _mm_div_ps(a, b);
-  return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
-}
-
-// Computes the approximations of the reciprocal square roots of the four single-precision floating point values of in.  https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in)
-{
-	
-  float32x4_t value = vrsqrteq_f32(in);
-  
-  // TODO: We must debug and ensure that rsqrt(0) and rsqrt(-0) yield proper values.
-  // Related code snippets can be found here: https://cpp.hotexamples.com/examples/-/-/vrsqrteq_f32/cpp-vrsqrteq_f32-function-examples.html
-  // If we adapt this function, we might be able to avoid special zero treatment in _mm_sqrt_ps
-  
-  value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
-  value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
-
-  // one more round to get better precision
-  value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
-
-  // another round for safety
-  value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
-
-  return value;
-}
-
-FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in)
-{
-  float32x4_t result = in;
-  
-  __m128 value = _mm_rsqrt_ps(in);
-
-  return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
-}
-
-
-// Computes the approximations of square roots of the four single-precision, floating-point values of a. First computes reciprocal square roots and then reciprocals of the four values. https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in)
-{
-#if defined(BUILD_IOS)
-  return vsqrtq_f32(in);
-#else
-  __m128 reciprocal = _mm_rsqrt_ps(in);
-  
-  // We must treat sqrt(in == 0) in a special way. At this point reciprocal contains gargabe due to vrsqrteq_f32(0) returning +inf.
-  // We assign 0 to reciprocal wherever required.
-  const float32x4_t vzero = vdupq_n_f32(0.0f);
-  const uint32x4_t mask = vceqq_f32(in, vzero);
-  reciprocal = vbslq_f32(mask, vzero, reciprocal);
-  
-  // sqrt(x) = x * (1 / sqrt(x))
-  return vmulq_f32(in, reciprocal);
-#endif
-}
-
-// Computes the approximation of the square root of the scalar single-precision floating point value of in.  https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in)
-{
-  float32x4_t value;
-  float32x4_t result = in;
-
-  value = _mm_sqrt_ps(in);
-  return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
-}
-
-
-// Computes the maximums of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b)
-{
-#if USE_PRECISE_MINMAX_IMPLEMENTATION
-  return vbslq_f32(vcltq_f32(b,a),a,b);
-#else
-  // Faster, but would give inconsitent rendering(e.g. holes, NaN pixels)
-  return vmaxq_f32(a, b);
-#endif
-}
-
-// Computes the minima of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b)
-{
-#if USE_PRECISE_MINMAX_IMPLEMENTATION
-  return vbslq_f32(vcltq_f32(a,b),a,b);
-#else
-  // Faster, but would give inconsitent rendering(e.g. holes, NaN pixels)
-  return vminq_f32(a, b);
-#endif
-}
-
-// Computes the maximum of the two lower scalar single-precision floating point values of a and b.  https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b)
-{
-  float32x4_t value;
-  float32x4_t result = a;
- 
-  value = _mm_max_ps(a, b);
-  return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
-}
-
-// Computes the minimum of the two lower scalar single-precision floating point values of a and b.  https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b)
-{
-  float32x4_t value;
-  float32x4_t result = a;
-
-    
-  value = _mm_min_ps(a, b);
-  return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
-}
-
-// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8 signed 16-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b)
-{
-  return (__m128i)vminq_s16((int16x8_t)a, (int16x8_t)b);
-}
-
-// epi versions of min/max
-// Computes the pariwise maximums of the four signed 32-bit integer values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b )
-{
-  return vmaxq_s32(a,b);
-}
-
-// Computes the pariwise minima of the four signed 32-bit integer values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b )
-{
-  return vminq_s32(a,b);
-}
-
-// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b)
-{
-  int16x8_t ret = vqdmulhq_s16((int16x8_t)a, (int16x8_t)b);
-  ret = vshrq_n_s16(ret, 1);
-  return (__m128i)ret;
-}
-
-// Computes pairwise add of each argument as single-precision, floating-point values a and b.
-//https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx
-FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b )
-{
-#if defined(__aarch64__)
-    return vpaddq_f32(a,b);
-#else
-// This does not work, no vpaddq...
-//	return (__m128) vpaddq_f32(a,b);
-        //
-        // get two f32x2_t values from a
-        // do vpadd
-        // put result in low half of f32x4 result
-        //
-        // get two f32x2_t values from b
-        // do vpadd
-        // put result in high half of f32x4 result
-        //
-        // combine
-        return vcombine_f32( vpadd_f32( vget_low_f32(a), vget_high_f32(a) ), vpadd_f32( vget_low_f32(b), vget_high_f32(b) ) );
-#endif
-}
-
-// ******************************************
-// Compare operations
-// ******************************************
-
-// Compares for less than https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b)
-{
-  return (__m128)vcltq_f32(a, b);
-}
-
-FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b)
-{
-  return (__m128) vmvnq_s32((__m128i)_mm_cmplt_ps(a,b));
-}
-
-// Compares for greater than. https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b)
-{
-  return (__m128)vcgtq_f32(a, b);
-}
-
-FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b)
-{
-  return (__m128) _mm_cmpgt_ps(a,b);
-}
-
-
-// Compares for greater than or equal. https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b)
-{
-  return (__m128)vcgeq_f32(a, b);
-}
-
-// Compares for less than or equal. https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b)
-{
-  return (__m128)vcleq_f32(a, b);
-}
-
-// Compares for equality. https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b)
-{
-  return (__m128)vceqq_f32(a, b);
-}
-
-// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers in b for less than. https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b)
-{
-  return (__m128i)vcltq_s32(a, b);
-}
-
-FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
-{
-  return (__m128i) vceqq_s32(a,b);
-}
-
-// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers in b for greater than. https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b)
-{
-  return (__m128i)vcgtq_s32(a, b);
-}
-
-// Compares the four 32-bit floats in a and b to check if any values are NaN. Ordered compare between each value returns true for "orderable" and false for "not orderable" (NaN). https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx
-// see also:
-// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean
-// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics
-FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b )
-{
-  // Note: NEON does not have ordered compare builtin
-  // Need to compare a eq a and b eq b to check for NaN
-  // Do AND of results to get final
-  return (__m128) vreinterpretq_f32_u32( vandq_u32( vceqq_f32(a,a), vceqq_f32(b,b) ) );
-}
-
-// Compares the lower single-precision floating point scalar values of a and b using a less than operation. : https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx
-FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b)
-{
-  uint32x4_t value;
-
-  value = vcltq_f32(a, b);
-  return vgetq_lane_u32(value, 0);
-}
-
-// Compares the lower single-precision floating point scalar values of a and b using a greater than operation. : https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx
-FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b)
-{
-  uint32x4_t value;
-
-  value = vcgtq_f32(a, b);
-  return vgetq_lane_u32(value, 0);
-}
-
-// Compares the lower single-precision floating point scalar values of a and b using a less than or equal operation. : https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx
-FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b)
-{
-  uint32x4_t value;
-
-  value = vcleq_f32(a, b);
-  return vgetq_lane_u32(value, 0);
-}
-
-// Compares the lower single-precision floating point scalar values of a and b using a greater than or equal operation. : https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx
-FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b)
-{
-  uint32x4_t value;
-
-  value = vcgeq_f32(a, b);
-  return vgetq_lane_u32(value, 0);
-}
-
-// Compares the lower single-precision floating point scalar values of a and b using an equality operation. : https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx
-FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b)
-{
-  uint32x4_t value;
-
-  value = vceqq_f32(a, b);
-  return vgetq_lane_u32(value, 0);
-}
-
-// Compares the lower single-precision floating point scalar values of a and b using an inequality operation. : https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx
-FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b)
-{
-  uint32x4_t value;
-
-  value = vceqq_f32(a, b);
-  return !vgetq_lane_u32(value, 0);
-}
-
-// according to the documentation, these intrinsics behave the same as the non-'u' versions.  We'll just alias them here.
-#define _mm_ucomilt_ss      _mm_comilt_ss
-#define _mm_ucomile_ss      _mm_comile_ss
-#define _mm_ucomigt_ss      _mm_comigt_ss
-#define _mm_ucomige_ss      _mm_comige_ss
-#define _mm_ucomieq_ss      _mm_comieq_ss
-#define _mm_ucomineq_ss     _mm_comineq_ss
-
-// ******************************************
-// Conversions
-// ******************************************
-
-// Converts the four single-precision, floating-point values of a to signed 32-bit integer values using truncate. https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a)
-{
-  return vcvtq_s32_f32(a);
-}
-
-// Converts the four signed 32-bit integer values of a to single-precision, floating-point values https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx
-FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a)
-{
-  return vcvtq_f32_s32(a);
-}
-
-// Converts the four single-precision, floating-point values of a to signed 32-bit integer values. https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx
-// *NOTE*. The default rounding mode on SSE is 'round to even', which ArmV7 does not support!
-// It is supported on ARMv8 however.
-FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a)
-{
-#if 1
-  return vcvtnq_s32_f32(a);
-#else
-  __m128 half = vdupq_n_f32(0.5f);
-  const __m128 sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(a), 31)));
-  const __m128 aPlusHalf = vaddq_f32(a, half);
-  const __m128 aRound = vsubq_f32(aPlusHalf, sign);
-  return vcvtq_s32_f32(aRound);
-#endif
-}
-
-// Moves the least significant 32 bits of a to a 32-bit integer. https://msdn.microsoft.com/en-us/library/5z7a9642%28v=vs.90%29.aspx
-FORCE_INLINE int _mm_cvtsi128_si32(__m128i a)
-{
-  return vgetq_lane_s32(a, 0);
-}
-
-// Moves 32-bit integer a to the least significant 32 bits of an __m128 object, zero extending the upper bits. https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx
-FORCE_INLINE __m128i _mm_cvtsi32_si128(int a)
-{
-  __m128i result = vdupq_n_s32(0);
-  return vsetq_lane_s32(a, result, 0);
-}
-
-
-// Applies a type cast to reinterpret four 32-bit floating point values passed in as a 128-bit parameter as packed 32-bit integers. https://msdn.microsoft.com/en-us/library/bb514099.aspx
-FORCE_INLINE __m128i _mm_castps_si128(__m128 a)
-{
-#if defined(__aarch64__)
-    return (__m128i)a;
-#else
-  return *(const __m128i *)&a;
-#endif
-}
-
-// Applies a type cast to reinterpret four 32-bit integers passed in as a 128-bit parameter as packed 32-bit floating point values. https://msdn.microsoft.com/en-us/library/bb514029.aspx
-FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a)
-{
-#if defined(__aarch64__)
-    return (__m128)a;
-#else
-  return *(const __m128 *)&a;
-#endif
-}
-
-// Loads 128-bit value. : https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx
-FORCE_INLINE __m128i _mm_load_si128(const __m128i *p)
-{
-  return vld1q_s32((int32_t *)p);
-}
-
-FORCE_INLINE __m128d _mm_castps_pd(const __m128 a)
-{
-  return *(const __m128d *)&a;
-}
-
-FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a)
-{
-  return *(const __m128d *)&a;
-}
-// ******************************************
-// Miscellaneous Operations
-// ******************************************
-
-// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and saturates. https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx
-FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b)
-{
-  return (__m128i)vcombine_s8(vqmovn_s16((int16x8_t)a), vqmovn_s16((int16x8_t)b));
-}
-
-// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned integers and saturates. https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)
-{
-  return (__m128i)vcombine_u8(vqmovun_s16((int16x8_t)a), vqmovun_s16((int16x8_t)b));
-}
-
-// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers and saturates. https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx
-FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b)
-{
-  return (__m128i)vcombine_s16(vqmovn_s32(a), vqmovn_s32(b));
-}
-
-// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower 8 signed or unsigned 8-bit integers in b.  https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx
-FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b)
-{
-  int8x8_t a1 = (int8x8_t)vget_low_s16((int16x8_t)a);
-  int8x8_t b1 = (int8x8_t)vget_low_s16((int16x8_t)b);
-
-  int8x8x2_t result = vzip_s8(a1, b1);
-
-  return (__m128i)vcombine_s8(result.val[0], result.val[1]);
-}
-
-// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the lower 4 signed or unsigned 16-bit integers in b.  https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx
-FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b)
-{
-  int16x4_t a1 = vget_low_s16((int16x8_t)a);
-  int16x4_t b1 = vget_low_s16((int16x8_t)b);
-
-  int16x4x2_t result = vzip_s16(a1, b1);
-
-  return (__m128i)vcombine_s16(result.val[0], result.val[1]);
-}
-
-// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the lower 2 signed or unsigned 32 - bit integers in b.  https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b)
-{
-  int32x2_t a1 = vget_low_s32(a);
-  int32x2_t b1 = vget_low_s32(b);
-
-  int32x2x2_t result = vzip_s32(a1, b1);
-
-  return vcombine_s32(result.val[0], result.val[1]);
-}
-
-// Selects and interleaves the lower two single-precision, floating-point values from a and b. https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx
-FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b)
-{
-  float32x2x2_t result = vzip_f32(vget_low_f32(a), vget_low_f32(b));
-  return vcombine_f32(result.val[0], result.val[1]);
-}
-
-// Selects and interleaves the upper two single-precision, floating-point values from a and b. https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx
-FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b)
-{
-  float32x2x2_t result = vzip_f32(vget_high_f32(a), vget_high_f32(b));
-  return vcombine_f32(result.val[0], result.val[1]);
-}
-
-// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper 8 signed or unsigned 8-bit integers in b.  https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b)
-{
-  int8x8_t a1 = (int8x8_t)vget_high_s16((int16x8_t)a);
-  int8x8_t b1 = (int8x8_t)vget_high_s16((int16x8_t)b);
-
-  int8x8x2_t result = vzip_s8(a1, b1);
-
-  return (__m128i)vcombine_s8(result.val[0], result.val[1]);
-}
-
-// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the upper 4 signed or unsigned 16-bit integers in b.  https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b)
-{
-  int16x4_t a1 = vget_high_s16((int16x8_t)a);
-  int16x4_t b1 = vget_high_s16((int16x8_t)b);
-
-  int16x4x2_t result = vzip_s16(a1, b1);
-
-  return (__m128i)vcombine_s16(result.val[0], result.val[1]);
-}
-
-// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the upper 2 signed or unsigned 32-bit integers in b.  https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx
-FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b)
-{
-  int32x2_t a1 = vget_high_s32(a);
-  int32x2_t b1 = vget_high_s32(b);
-
-  int32x2x2_t result = vzip_s32(a1, b1);
-
-  return vcombine_s32(result.val[0], result.val[1]);
-}
-
-// Extracts the selected signed or unsigned 16-bit integer from a and zero extends.  https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx
-#define _mm_extract_epi16( a, imm ) vgetq_lane_s16((int16x8_t)a, imm)
-
-// ******************************************
-// Streaming Extensions
-// ******************************************
-
-// Guarantees that every preceding store is globally visible before any subsequent store.  https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx
-FORCE_INLINE void _mm_sfence(void)
-{
-  __sync_synchronize();
-}
-
-// Stores the data in a to the address p without polluting the caches.  If the cache line containing address p is already in the cache, the cache will be updated.Address p must be 16 - byte aligned.  https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx
-FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a)
-{
-  *p = a;
-}
-
-// Cache line containing p is flushed and invalidated from all caches in the coherency domain. : https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx
-FORCE_INLINE void _mm_clflush(void const*p)
-{
-  // no corollary for Neon?
-}
-
-FORCE_INLINE __m128i _mm_set_epi64x(int64_t a, int64_t b)
-{
-  // Stick to the flipped behavior of x86.
-  int64_t __attribute__((aligned(16))) data[2] = { b, a };
-  return (__m128i)vld1q_s64(data);
-}
-
-FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i)
-{
-  return (__m128i)vmovq_n_s64(_i);
-}
-
-#if defined(__aarch64__)
-FORCE_INLINE __m128 _mm_blendv_ps(__m128 a, __m128 b, __m128 c)
-{
-    int32x4_t mask = vshrq_n_s32(__m128i(c),31);
-    return vbslq_f32( uint32x4_t(mask), b, a);
-}
-
-FORCE_INLINE __m128i _mm_load4epu8_epi32(__m128i *ptr)
-{
-    uint8x8_t  t0 = vld1_u8((uint8_t*)ptr);
-    uint16x8_t t1 = vmovl_u8(t0);
-    uint32x4_t t2 = vmovl_u16(vget_low_u16(t1));
-    return vreinterpretq_s32_u32(t2);
-}
-
-FORCE_INLINE __m128i _mm_load4epu16_epi32(__m128i *ptr)
-{
-    uint16x8_t t0 = vld1q_u16((uint16_t*)ptr);
-    uint32x4_t t1 = vmovl_u16(vget_low_u16(t0));
-    return vreinterpretq_s32_u32(t1);
-}
-
-FORCE_INLINE __m128i _mm_load4epi8_f32(__m128i *ptr)
-{
-    int8x8_t    t0 = vld1_s8((int8_t*)ptr);
-    int16x8_t   t1 = vmovl_s8(t0);
-    int32x4_t   t2 = vmovl_s16(vget_low_s16(t1));
-    float32x4_t t3 = vcvtq_f32_s32(t2);
-    return vreinterpretq_s32_f32(t3);
-}
-
-FORCE_INLINE __m128i _mm_load4epu8_f32(__m128i *ptr)
-{
-    uint8x8_t   t0 = vld1_u8((uint8_t*)ptr);
-    uint16x8_t  t1 = vmovl_u8(t0);
-    uint32x4_t  t2 = vmovl_u16(vget_low_u16(t1));
-    return vreinterpretq_s32_u32(t2);
-}
-
-FORCE_INLINE __m128i _mm_load4epi16_f32(__m128i *ptr)
-{
-    int16x8_t   t0 = vld1q_s16((int16_t*)ptr);
-    int32x4_t   t1 = vmovl_s16(vget_low_s16(t0));
-    float32x4_t t2 = vcvtq_f32_s32(t1);
-    return vreinterpretq_s32_f32(t2);
-}
-
-FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b)
-{
-    return (__m128i)vcombine_u8(vqmovun_s16((int16x8_t)a), vqmovun_s16((int16x8_t)b));
-}
-
-FORCE_INLINE __m128i _mm_stream_load_si128(__m128i* ptr)
-{
-    // No non-temporal load on a single register on ARM.
-    return vreinterpretq_s32_u8(vld1q_u8((uint8_t*)ptr));
-}
-
-FORCE_INLINE void _mm_stream_ps(float* ptr, __m128i a)
-{
-    // No non-temporal store on a single register on ARM.
-    vst1q_f32((float*)ptr, vreinterpretq_f32_s32(a));
-}
-
-FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b)
-{
-    return vreinterpretq_s32_u32(vminq_u32(vreinterpretq_u32_s32(a), vreinterpretq_u32_s32(b)));
-}
-
-FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b)
-{
-    return vreinterpretq_s32_u32(vmaxq_u32(vreinterpretq_u32_s32(a), vreinterpretq_u32_s32(b)));
-}
-
-FORCE_INLINE __m128 _mm_abs_ps(__m128 a)
-{
-    return vabsq_f32(a);
-}
-
-FORCE_INLINE __m128 _mm_madd_ps(__m128 a, __m128 b, __m128 c)
-{
-    return vmlaq_f32(c, a, b);
-}
-
-FORCE_INLINE __m128 _mm_msub_ps(__m128 a, __m128 b, __m128 c)
-{
-    return vmlsq_f32(c, a, b);
-}
-
-FORCE_INLINE __m128i _mm_abs_epi32(__m128i a)
-{
-  return vabsq_s32(a);
-}
-#endif  //defined(__aarch64__)
-
-// Count the number of bits set to 1 in unsigned 32-bit integer a, and
-// return that count in dst.
-// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32
-FORCE_INLINE int _mm_popcnt_u32(unsigned int a)
-{
-  return (int)vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t)a)));
-}
-
-// Count the number of bits set to 1 in unsigned 64-bit integer a, and
-// return that count in dst.
-// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64
-FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a)
-{
-  return (int64_t)vaddlv_u8(vcnt_u8(vcreate_u8(a)));
-}
-
-#endif

+ 0 - 61
thirdparty/embree-aarch64/common/math/constants.cpp

@@ -1,61 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#if defined(__aarch64__)
-#include <arm_neon.h>
-#endif
-
-#include "constants.h"
-
-namespace embree
-{
-  TrueTy True;
-  FalseTy False;
-  ZeroTy zero;
-  OneTy one;
-  NegInfTy neg_inf;
-  PosInfTy inf;
-  PosInfTy pos_inf;
-  NaNTy nan;
-  UlpTy ulp;
-  PiTy pi;
-  OneOverPiTy one_over_pi;
-  TwoPiTy two_pi;
-  OneOverTwoPiTy one_over_two_pi;
-  FourPiTy four_pi;
-  OneOverFourPiTy one_over_four_pi;
-  StepTy step;
-  ReverseStepTy reverse_step;
-  EmptyTy empty;
-  UndefinedTy undefined;
-
-#if defined(__aarch64__)
-const uint32x4_t movemask_mask = { 1, 2, 4, 8 };
-const uint32x4_t vzero = { 0, 0, 0, 0 };
-const uint32x4_t v0x80000000 = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
-const uint32x4_t v0x7fffffff = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff };
-const uint32x4_t v000F = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
-const uint32x4_t v00F0 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000 };
-const uint32x4_t v00FF = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
-const uint32x4_t v0F00 = { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 };
-const uint32x4_t v0F0F = { 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF };
-const uint32x4_t v0FF0 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
-const uint32x4_t v0FFF = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
-const uint32x4_t vF000 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
-const uint32x4_t vF00F = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF };
-const uint32x4_t vF0F0 = { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 };
-const uint32x4_t vF0FF = { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
-const uint32x4_t vFF00 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
-const uint32x4_t vFF0F = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF };
-const uint32x4_t vFFF0 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
-const uint32x4_t vFFFF = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
-const uint8x16_t v0022 = {0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11};
-const uint8x16_t v1133 = {4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15};
-const uint8x16_t v0101 = {0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7};
-const float32x4_t vOne = { 1.0f, 1.0f, 1.0f, 1.0f };
-const float32x4_t vmOne = { -1.0f, -1.0f, -1.0f, -1.0f };
-const float32x4_t vInf = { INFINITY, INFINITY, INFINITY, INFINITY };
-const float32x4_t vmInf = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
-#endif
-
-}

+ 0 - 49
thirdparty/embree-aarch64/common/tasking/taskschedulergcd.h

@@ -1,49 +0,0 @@
-#pragma once
-
-#include "../sys/platform.h"
-#include "../sys/alloc.h"
-#include "../sys/barrier.h"
-#include "../sys/thread.h"
-#include "../sys/mutex.h"
-#include "../sys/condition.h"
-#include "../sys/ref.h"
-
-#include <dispatch/dispatch.h>
-
-namespace embree
-{
-  struct TaskScheduler
-  {
-    /*! initializes the task scheduler */
-    static void create(size_t numThreads, bool set_affinity, bool start_threads);
-
-    /*! destroys the task scheduler again */
-    static void destroy() {}
-
-    /* returns the ID of the current thread */
-    static __forceinline size_t threadID()
-    {
-      return threadIndex();
-    }
-
-    /* returns the index (0..threadCount-1) of the current thread */
-    static __forceinline size_t threadIndex()
-    {
-        currentThreadIndex = (currentThreadIndex + 1) % GCDNumThreads;
-        return currentThreadIndex;
-    }
-
-    /* returns the total number of threads */
-    static __forceinline size_t threadCount()
-    {
-        return GCDNumThreads;
-    }
-
-    private:
-      static size_t GCDNumThreads;
-      static size_t currentThreadIndex;
-
-  };
-
-};
-

+ 0 - 28
thirdparty/embree-aarch64/kernels/builders/primrefgen.h

@@ -1,28 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "../common/scene.h"
-#include "../common/primref.h"
-#include "../common/primref_mb.h"
-#include "priminfo.h"
-#include "bvh_builder_morton.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    PrimInfo createPrimRefArray(Geometry* geometry, unsigned int geomID, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor);
-   
-    PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor);
-   
-    PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime = 0);
-
-    PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f));
-
-    template<typename Mesh>
-      size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor);
-  }
-}
-

+ 0 - 199
thirdparty/embree-aarch64/kernels/common/instance_stack.h

@@ -1,199 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "rtcore.h"
-
-namespace embree {
-namespace instance_id_stack {
-
-static_assert(RTC_MAX_INSTANCE_LEVEL_COUNT > 0, 
-              "RTC_MAX_INSTANCE_LEVEL_COUNT must be greater than 0.");
-
-/*******************************************************************************
- * Instance ID stack manipulation.
- * This is used from the instance intersector.
- ******************************************************************************/
-
-/* 
- * Push an instance to the stack. 
- */
-RTC_FORCEINLINE bool push(RTCIntersectContext* context, 
-                          unsigned instanceId)
-{
-#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
-  const bool spaceAvailable = context->instStackSize < RTC_MAX_INSTANCE_LEVEL_COUNT;
-  /* We assert here because instances are silently dropped when the stack is full. 
-     This might be quite hard to find in production. */
-  assert(spaceAvailable); 
-  if (likely(spaceAvailable))
-    context->instID[context->instStackSize++] = instanceId;
-  return spaceAvailable;
-#else
-  const bool spaceAvailable = (context->instID[0] == RTC_INVALID_GEOMETRY_ID);
-  assert(spaceAvailable); 
-  if (likely(spaceAvailable))
-    context->instID[0] = instanceId;
-  return spaceAvailable;
-#endif
-}
-
-
-/* 
- * Pop the last instance pushed to the stack. 
- * Do not call on an empty stack. 
- */
-RTC_FORCEINLINE void pop(RTCIntersectContext* context)
-{
-  assert(context);
-#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
-  assert(context->instStackSize > 0);
-  context->instID[--context->instStackSize] = RTC_INVALID_GEOMETRY_ID;
-#else
-  assert(context->instID[0] != RTC_INVALID_GEOMETRY_ID);
-  context->instID[0] = RTC_INVALID_GEOMETRY_ID;
-#endif
-}
-
-/*******************************************************************************
- * Optimized instance id stack copy.
- * The copy() function at the bottom of this block will either copy full
- * stacks or copy only until the last valid element has been copied, depending
- * on RTC_MAX_INSTANCE_LEVEL_COUNT.
- ******************************************************************************/
-
-/*
- * Plain array assignment. This works for scalar->scalar,
- * scalar->vector, and vector->vector.
- */
-template <class Src, class Tgt>
-RTC_FORCEINLINE void level_copy(unsigned level, Src* src, Tgt* tgt)
-{
-  tgt[level] = src[level];
-}
-
-/*
- * Masked SIMD vector->vector store.
- */
-template <int K>
-RTC_FORCEINLINE void level_copy(unsigned level, const vuint<K>* src, vuint<K>* tgt, const vbool<K>& mask)
-{
-  vuint<K>::storeu(mask, tgt + level, src[level]);
-}
-
-/*
- * Masked scalar->SIMD vector store.
- */
-template <int K>
-RTC_FORCEINLINE void level_copy(unsigned level, const unsigned* src, vuint<K>* tgt, const vbool<K>& mask)
-{
-  vuint<K>::store(mask, tgt + level, src[level]);
-}
-
-/*
- * Indexed assign from vector to scalar.
- */
-template <int K>
-RTC_FORCEINLINE void level_copy(unsigned level, const vuint<K>* src, unsigned* tgt, const size_t& idx)
-{
-  tgt[level] = src[level][idx];
-}
-
-/*
- * Indexed assign from scalar to vector.
- */
-template <int K>
-RTC_FORCEINLINE void level_copy(unsigned level, const unsigned* src, vuint<K>* tgt, const size_t& idx)
-{
-  tgt[level][idx] = src[level];
-}
-
-/*
- * Indexed assign from vector to vector.
- */
-template <int K>
-RTC_FORCEINLINE void level_copy(unsigned level, const vuint<K>* src, vuint<K>* tgt, const size_t& i, const size_t& j)
-{
-  tgt[level][j] = src[level][i];
-}
-
-/*
- * Check if the given stack level is valid.
- * These are only used for large max stack sizes.
- */
-RTC_FORCEINLINE bool level_valid(unsigned level, const unsigned* stack)
-{
-  return stack[level] != RTC_INVALID_GEOMETRY_ID;
-}
-RTC_FORCEINLINE bool level_valid(unsigned level, const unsigned* stack, const size_t& /*i*/)
-{
-  return stack[level] != RTC_INVALID_GEOMETRY_ID;
-}
-template <int K>
-RTC_FORCEINLINE bool level_valid(unsigned level, const unsigned* stack, const vbool<K>& /*mask*/)
-{
-  return stack[level] != RTC_INVALID_GEOMETRY_ID;
-}
-
-template <int K>
-RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack)
-{
-  return any(stack[level] != RTC_INVALID_GEOMETRY_ID);
-}
-template <int K>
-RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack, const vbool<K>& mask)
-{
-  return any(mask & (stack[level] != RTC_INVALID_GEOMETRY_ID));
-}
-
-template <int K>
-RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack, const size_t& i)
-{
-  return stack[level][i] != RTC_INVALID_GEOMETRY_ID;
-}
-template <int K>
-RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack, const size_t& i, const size_t& /*j*/)
-{
-  return stack[level][i] != RTC_INVALID_GEOMETRY_ID;
-}
-
-/*
- * Copy an instance ID stack.
- *
- * This function automatically selects a LevelFunctor from the above Assign 
- * structs.
- */
-template <class Src, class Tgt, class... Args>
-RTC_FORCEINLINE void copy(Src src, Tgt tgt, Args&&... args)
-{
-#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
-  /* 
-   * Avoid all loops for only one level. 
-   */
-  level_copy(0, src, tgt, std::forward<Args>(args)...);
-
-#elif (RTC_MAX_INSTANCE_LEVEL_COUNT <= 4)
-  /* 
-   * It is faster to avoid the valid test for low level counts.
-   * Just copy the whole stack.
-   */
-  for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
-    level_copy(l, src, tgt, std::forward<Args>(args)...);
-
-#else
-  /* 
-   * For general stack sizes, it pays off to test for validity.
-   */
-  bool valid = true;
-  for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT && valid; ++l)
-  {
-    level_copy(l, src, tgt, std::forward<Args>(args)...);
-    valid = level_valid(l, src, std::forward<Args>(args)...);
-  }
-#endif
-}
-
-} // namespace instance_id_stack
-} // namespace embree
-

+ 0 - 341
thirdparty/embree-aarch64/kernels/common/scene_curves.h

@@ -1,341 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "default.h"
-#include "geometry.h"
-#include "buffer.h"
-
-namespace embree
-{
-  /*! represents an array of bicubic bezier curves */
-  struct CurveGeometry : public Geometry
-  {
-    /*! type of this geometry */
-    static const Geometry::GTypeMask geom_type = Geometry::MTY_CURVE4;
-
-  public:
-    
-    /*! bezier curve construction */
-    CurveGeometry (Device* device, Geometry::GType gtype);
-    
-  public:
-    void setMask(unsigned mask);
-    void setNumTimeSteps (unsigned int numTimeSteps);
-    void setVertexAttributeCount (unsigned int N);
-    void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
-    void* getBuffer(RTCBufferType type, unsigned int slot);
-    void updateBuffer(RTCBufferType type, unsigned int slot);
-    void commit();
-    bool verify();
-    void setTessellationRate(float N);
-    void setMaxRadiusScale(float s);
-    void addElementsToCount (GeometryCounts & counts) const;
-
-  public:
-    
-    /*! returns the number of vertices */
-    __forceinline size_t numVertices() const {
-      return vertices[0].size();
-    }
-
-    /*! returns the i'th curve */
-    __forceinline const unsigned int& curve(size_t i) const {
-      return curves[i];
-    }
-
-    /*! returns i'th vertex of the first time step */
-    __forceinline Vec3ff vertex(size_t i) const {
-      return vertices0[i];
-    }
-
-    /*! returns i'th normal of the first time step */
-    __forceinline Vec3fa normal(size_t i) const {
-      return normals0[i];
-    }
-
-    /*! returns i'th tangent of the first time step */
-    __forceinline Vec3ff tangent(size_t i) const {
-      return tangents0[i];
-    }
-
-    /*! returns i'th normal derivative of the first time step */
-    __forceinline Vec3fa dnormal(size_t i) const {
-      return dnormals0[i];
-    }
-
-    /*! returns i'th radius of the first time step */
-    __forceinline float radius(size_t i) const {
-      return vertices0[i].w;
-    }
-
-    /*! returns i'th vertex of itime'th timestep */
-    __forceinline Vec3ff vertex(size_t i, size_t itime) const {
-      return vertices[itime][i];
-    }
-
-    /*! returns i'th normal of itime'th timestep */
-    __forceinline Vec3fa normal(size_t i, size_t itime) const {
-      return normals[itime][i];
-    }
-
-    /*! returns i'th tangent of itime'th timestep */
-    __forceinline Vec3ff tangent(size_t i, size_t itime) const {
-      return tangents[itime][i];
-    }
-
-    /*! returns i'th normal derivative of itime'th timestep */
-    __forceinline Vec3fa dnormal(size_t i, size_t itime) const {
-      return dnormals[itime][i];
-    }
-
-    /*! returns i'th radius of itime'th timestep */
-    __forceinline float radius(size_t i, size_t itime) const {
-      return vertices[itime][i].w;
-    }
-
-    /*! gathers the curve starting with i'th vertex */
-    __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i) const
-    {
-      p0 = vertex(i+0);
-      p1 = vertex(i+1);
-      p2 = vertex(i+2);
-      p3 = vertex(i+3);
-    }
-
-    /*! gathers the curve starting with i'th vertex of itime'th timestep */
-    __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, size_t itime) const
-    {
-      p0 = vertex(i+0,itime);
-      p1 = vertex(i+1,itime);
-      p2 = vertex(i+2,itime);
-      p3 = vertex(i+3,itime);
-    }
-
-    /*! gathers the curve starting with i'th vertex */
-    __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i) const
-    {
-      p0 = vertex(i+0);
-      p1 = vertex(i+1);
-      p2 = vertex(i+2);
-      p3 = vertex(i+3);
-      n0 = normal(i+0);
-      n1 = normal(i+1);
-      n2 = normal(i+2);
-      n3 = normal(i+3);
-    }
-
-    /*! gathers the curve starting with i'th vertex of itime'th timestep */
-    __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, size_t itime) const
-    {
-      p0 = vertex(i+0,itime);
-      p1 = vertex(i+1,itime);
-      p2 = vertex(i+2,itime);
-      p3 = vertex(i+3,itime);
-      n0 = normal(i+0,itime);
-      n1 = normal(i+1,itime);
-      n2 = normal(i+2,itime);
-      n3 = normal(i+3,itime);
-    }
-
-    /*! prefetches the curve starting with i'th vertex of itime'th timestep */
-    __forceinline void prefetchL1_vertices(size_t i) const
-    {
-      prefetchL1(vertices0.getPtr(i)+0);
-      prefetchL1(vertices0.getPtr(i)+64);
-    }
-
-    /*! prefetches the curve starting with i'th vertex of itime'th timestep */
-    __forceinline void prefetchL2_vertices(size_t i) const
-    {
-      prefetchL2(vertices0.getPtr(i)+0);
-      prefetchL2(vertices0.getPtr(i)+64);
-    }  
-
-    /*! loads curve vertices for specified time */
-    __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, float time) const
-    {
-      float ftime;
-      const size_t itime = timeSegment(time, ftime);
-
-      const float t0 = 1.0f - ftime;
-      const float t1 = ftime;
-      Vec3ff a0,a1,a2,a3;
-      gather(a0,a1,a2,a3,i,itime);
-      Vec3ff b0,b1,b2,b3;
-      gather(b0,b1,b2,b3,i,itime+1);
-      p0 = madd(Vec3ff(t0),a0,t1*b0);
-      p1 = madd(Vec3ff(t0),a1,t1*b1);
-      p2 = madd(Vec3ff(t0),a2,t1*b2);
-      p3 = madd(Vec3ff(t0),a3,t1*b3);
-    }
-
-    /*! loads curve vertices for specified time */
-    __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, float time) const
-    {
-      float ftime;
-      const size_t itime = timeSegment(time, ftime);
-
-      const float t0 = 1.0f - ftime;
-      const float t1 = ftime;
-      Vec3ff a0,a1,a2,a3; Vec3fa an0,an1,an2,an3;
-      gather(a0,a1,a2,a3,an0,an1,an2,an3,i,itime);
-      Vec3ff b0,b1,b2,b3; Vec3fa bn0,bn1,bn2,bn3;
-      gather(b0,b1,b2,b3,bn0,bn1,bn2,bn3,i,itime+1);
-      p0 = madd(Vec3ff(t0),a0,t1*b0);
-      p1 = madd(Vec3ff(t0),a1,t1*b1);
-      p2 = madd(Vec3ff(t0),a2,t1*b2);
-      p3 = madd(Vec3ff(t0),a3,t1*b3);
-      n0 = madd(Vec3ff(t0),an0,t1*bn0);
-      n1 = madd(Vec3ff(t0),an1,t1*bn1);
-      n2 = madd(Vec3ff(t0),an2,t1*bn2);
-      n3 = madd(Vec3ff(t0),an3,t1*bn3);
-    }
-
-    template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
-    __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const
-    {
-      Vec3ff v0,v1,v2,v3; Vec3fa n0,n1,n2,n3;
-      unsigned int vertexID = curve(primID);
-      gather(v0,v1,v2,v3,n0,n1,n2,n3,vertexID,itime);
-      SourceCurve3ff ccurve(v0,v1,v2,v3);
-      SourceCurve3fa ncurve(n0,n1,n2,n3);
-      ccurve = enlargeRadiusToMinWidth(context,this,ray_org,ccurve);
-      return TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
-    }
-
-    template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
-    __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const
-    {
-      float ftime;
-      const size_t itime = timeSegment(time, ftime);
-      const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+0);
-      const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+1);
-      return clerp(curve0,curve1,ftime);
-    }
-
-    /*! gathers the hermite curve starting with i'th vertex */
-    __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i) const
-    {
-      p0 = vertex (i+0);
-      p1 = vertex (i+1);
-      t0 = tangent(i+0);
-      t1 = tangent(i+1);
-    }
-
-    /*! gathers the hermite curve starting with i'th vertex of itime'th timestep */
-    __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, size_t itime) const
-    {
-      p0 = vertex (i+0,itime);
-      p1 = vertex (i+1,itime);
-      t0 = tangent(i+0,itime);
-      t1 = tangent(i+1,itime);
-    }
-
-    /*! loads curve vertices for specified time */
-    __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, float time) const
-    {
-      float ftime;
-      const size_t itime = timeSegment(time, ftime);
-      const float f0 = 1.0f - ftime, f1 = ftime;
-      Vec3ff ap0,at0,ap1,at1;
-      gather_hermite(ap0,at0,ap1,at1,i,itime);
-      Vec3ff bp0,bt0,bp1,bt1;
-      gather_hermite(bp0,bt0,bp1,bt1,i,itime+1);
-      p0 = madd(Vec3ff(f0),ap0,f1*bp0);
-      t0 = madd(Vec3ff(f0),at0,f1*bt0);
-      p1 = madd(Vec3ff(f0),ap1,f1*bp1);
-      t1 = madd(Vec3ff(f0),at1,f1*bt1);
-    }
-
-    /*! gathers the hermite curve starting with i'th vertex */
-    __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i) const
-    {
-      p0 = vertex (i+0);
-      p1 = vertex (i+1);
-      t0 = tangent(i+0);
-      t1 = tangent(i+1);
-      n0 = normal(i+0);
-      n1 = normal(i+1);
-      dn0 = dnormal(i+0);
-      dn1 = dnormal(i+1);
-    }
-
-    /*! gathers the hermite curve starting with i'th vertex of itime'th timestep */
-    __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, size_t itime) const
-    {
-      p0 = vertex (i+0,itime);
-      p1 = vertex (i+1,itime);
-      t0 = tangent(i+0,itime);
-      t1 = tangent(i+1,itime);
-      n0 = normal(i+0,itime);
-      n1 = normal(i+1,itime);
-      dn0 = dnormal(i+0,itime);
-      dn1 = dnormal(i+1,itime);
-    }
-
-    /*! loads curve vertices for specified time */
-    __forceinline void gather_hermite(Vec3ff& p0, Vec3fa& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3fa& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, float time) const
-    {
-      float ftime;
-      const size_t itime = timeSegment(time, ftime);
-      const float f0 = 1.0f - ftime, f1 = ftime;
-      Vec3ff ap0,at0,ap1,at1; Vec3fa an0,adn0,an1,adn1;
-      gather_hermite(ap0,at0,an0,adn0,ap1,at1,an1,adn1,i,itime);
-      Vec3ff bp0,bt0,bp1,bt1; Vec3fa bn0,bdn0,bn1,bdn1;
-      gather_hermite(bp0,bt0,bn0,bdn0,bp1,bt1,bn1,bdn1,i,itime+1);
-      p0 = madd(Vec3ff(f0),ap0,f1*bp0);
-      t0 = madd(Vec3ff(f0),at0,f1*bt0);
-      n0 = madd(Vec3ff(f0),an0,f1*bn0);
-      dn0= madd(Vec3ff(f0),adn0,f1*bdn0);
-      p1 = madd(Vec3ff(f0),ap1,f1*bp1);
-      t1 = madd(Vec3ff(f0),at1,f1*bt1);
-      n1 = madd(Vec3ff(f0),an1,f1*bn1);
-      dn1= madd(Vec3ff(f0),adn1,f1*bdn1);
-    }
-
-    template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
-      __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const
-    {
-      Vec3ff v0,t0,v1,t1; Vec3fa n0,dn0,n1,dn1;
-      unsigned int vertexID = curve(primID);
-      gather_hermite(v0,t0,n0,dn0,v1,t1,n1,dn1,vertexID,itime);
-
-      SourceCurve3ff ccurve(v0,t0,v1,t1);
-      SourceCurve3fa ncurve(n0,dn0,n1,dn1);
-      ccurve = enlargeRadiusToMinWidth(context,this,ray_org,ccurve);
-      return TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
-    }
-
-    template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
-    __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const
-    {
-      float ftime;
-      const size_t itime = timeSegment(time, ftime);
-      const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+0);
-      const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+1);
-      return clerp(curve0,curve1,ftime);
-    }
-
-  private:
-    void resizeBuffers(unsigned int numSteps);
-
-  public:
-    BufferView<unsigned int> curves;        //!< array of curve indices
-    BufferView<Vec3ff> vertices0;           //!< fast access to first vertex buffer
-    BufferView<Vec3fa> normals0;            //!< fast access to first normal buffer
-    BufferView<Vec3ff> tangents0;           //!< fast access to first tangent buffer
-    BufferView<Vec3fa> dnormals0;           //!< fast access to first normal derivative buffer
-    vector<BufferView<Vec3ff>> vertices;    //!< vertex array for each timestep
-    vector<BufferView<Vec3fa>> normals;     //!< normal array for each timestep
-    vector<BufferView<Vec3ff>> tangents;    //!< tangent array for each timestep
-    vector<BufferView<Vec3fa>> dnormals;    //!< normal derivative array for each timestep
-    BufferView<char> flags;                 //!< start, end flag per segment
-    vector<BufferView<char>> vertexAttribs; //!< user buffers
-    int tessellationRate;                   //!< tessellation rate for flat curve
-    float maxRadiusScale = 1.0;             //!< maximal min-width scaling of curve radii
-  };
-  
-  DECLARE_ISA_FUNCTION(CurveGeometry*, createCurves, Device* COMMA Geometry::GType);
-}

+ 0 - 21
thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bezier_curve.h

@@ -1,21 +0,0 @@
-// Copyright 2020 Light Transport Entertainment Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "curve_intersector_virtual.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    void AddVirtualCurveBezierCurveInterector4i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBezierCurveInterector4v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBezierCurveInterector4iMB(VirtualCurveIntersector &prim);
-#if defined(__AVX__)
-    void AddVirtualCurveBezierCurveInterector8i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBezierCurveInterector8v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBezierCurveInterector8iMB(VirtualCurveIntersector &prim);
-#endif
-  }
-}

+ 0 - 21
thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bspline_curve.h

@@ -1,21 +0,0 @@
-// Copyright 2020 Light Transport Entertainment Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "curve_intersector_virtual.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    void AddVirtualCurveBSplineCurveInterector4i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBSplineCurveInterector4v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBSplineCurveInterector4iMB(VirtualCurveIntersector &prim);
-#if defined(__AVX__)
-    void AddVirtualCurveBSplineCurveInterector8i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBSplineCurveInterector8v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveBSplineCurveInterector8iMB(VirtualCurveIntersector &prim);
-#endif
-  }
-}

+ 0 - 21
thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_catmullrom_curve.h

@@ -1,21 +0,0 @@
-// Copyright 2020 Light Transport Entertainment Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "curve_intersector_virtual.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    void AddVirtualCurveCatmullRomCurveInterector4i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveCatmullRomCurveInterector4v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveCatmullRomCurveInterector4iMB(VirtualCurveIntersector &prim);
-#if defined(__AVX__)
-    void AddVirtualCurveCatmullRomCurveInterector8i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveCatmullRomCurveInterector8v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveCatmullRomCurveInterector8iMB(VirtualCurveIntersector &prim);
-#endif
-  }
-}

+ 0 - 21
thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_hermite_curve.h

@@ -1,21 +0,0 @@
-// Copyright 2020 Light Transport Entertainment Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "curve_intersector_virtual.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    void AddVirtualCurveHermiteCurveInterector4i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveHermiteCurveInterector4v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveHermiteCurveInterector4iMB(VirtualCurveIntersector &prim);
-#if defined(__AVX__)
-    void AddVirtualCurveHermiteCurveInterector8i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveHermiteCurveInterector8v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveHermiteCurveInterector8iMB(VirtualCurveIntersector &prim);
-#endif
-  }
-}

+ 0 - 21
thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_linear_curve.h

@@ -1,21 +0,0 @@
-// Copyright 2020 Light Transport Entertainment Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "curve_intersector_virtual.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    void AddVirtualCurveLinearCurveInterector4i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveLinearCurveInterector4v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveLinearCurveInterector4iMB(VirtualCurveIntersector &prim);
-#if defined(__AVX__)
-    void AddVirtualCurveLinearCurveInterector8i(VirtualCurveIntersector &prim);
-    void AddVirtualCurveLinearCurveInterector8v(VirtualCurveIntersector &prim);
-    void AddVirtualCurveLinearCurveInterector8iMB(VirtualCurveIntersector &prim);
-#endif
-  }
-}

+ 0 - 22
thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_point.h

@@ -1,22 +0,0 @@
-// Copyright 2020 Light Transport Entertainment Inc.
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "curve_intersector_virtual.h"
-
-namespace embree
-{
-  namespace isa
-  {
-    void AddVirtualCurvePointInterector4i(VirtualCurveIntersector &prim);
-    void AddVirtualCurvePointInterector4v(VirtualCurveIntersector &prim);
-    void AddVirtualCurvePointInterector4iMB(VirtualCurveIntersector &prim);
-
-#if defined (__AVX__)
-    void AddVirtualCurvePointInterector8i(VirtualCurveIntersector &prim);
-    void AddVirtualCurvePointInterector8v(VirtualCurveIntersector &prim);
-    void AddVirtualCurvePointInterector8iMB(VirtualCurveIntersector &prim);
-#endif
-  }
-}

+ 0 - 493
thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_moeller.h

@@ -1,493 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "subgrid.h"
-#include "quad_intersector_moeller.h"
-
-namespace embree
-{
-  namespace isa
-  {
-
-    /* ----------------------------- */
-    /* -- single ray intersectors -- */
-    /* ----------------------------- */
-
-    template<int M>
-      __forceinline void interpolateUV(MoellerTrumboreHitM<M> &hit,const GridMesh::Grid &g, const SubGrid& subgrid) 
-    {
-      /* correct U,V interpolation across the entire grid */
-      const vint<M> sx((int)subgrid.x());
-      const vint<M> sy((int)subgrid.y());
-      const vint<M> sxM(sx + vint<M>(0,1,1,0));
-      const vint<M> syM(sy + vint<M>(0,0,1,1));
-      const float inv_resX = rcp((float)((int)g.resX-1));
-      const float inv_resY = rcp((float)((int)g.resY-1));          
-      hit.U = (hit.U + (vfloat<M>)sxM * hit.absDen) * inv_resX;
-      hit.V = (hit.V + (vfloat<M>)syM * hit.absDen) * inv_resY;
-    }
-    
-    template<int M, bool filter>
-      struct SubGridQuadMIntersector1MoellerTrumbore;
-
-    template<int M, bool filter>
-      struct SubGridQuadMIntersector1MoellerTrumbore
-      {
-        __forceinline SubGridQuadMIntersector1MoellerTrumbore() {}
-
-        __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
-
-        __forceinline void intersect(RayHit& ray, IntersectContext* context,
-                                     const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
-                                     const GridMesh::Grid &g, const SubGrid& subgrid) const
-        {
-          MoellerTrumboreHitM<M> hit;
-          MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
-          Intersect1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
-
-          /* intersect first triangle */
-          if (intersector.intersect(ray,v0,v1,v3,hit)) 
-          {
-            interpolateUV<M>(hit,g,subgrid);
-            epilog(hit.valid,hit);
-          }
-
-          /* intersect second triangle */
-          if (intersector.intersect(ray,v2,v3,v1,hit)) 
-          {
-            hit.U = hit.absDen - hit.U;
-            hit.V = hit.absDen - hit.V;
-            interpolateUV<M>(hit,g,subgrid);
-            epilog(hit.valid,hit);
-          }
-        }
-      
-        __forceinline bool occluded(Ray& ray, IntersectContext* context,
-                                    const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
-                                    const GridMesh::Grid &g, const SubGrid& subgrid) const
-        {
-          MoellerTrumboreHitM<M> hit;
-          MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
-          Occluded1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
-          
-          /* intersect first triangle */
-          if (intersector.intersect(ray,v0,v1,v3,hit)) 
-          {
-            interpolateUV<M>(hit,g,subgrid);
-            if (epilog(hit.valid,hit))
-              return true;
-          }
-
-          /* intersect second triangle */
-          if (intersector.intersect(ray,v2,v3,v1,hit)) 
-          {
-            hit.U = hit.absDen - hit.U;
-            hit.V = hit.absDen - hit.V;
-            interpolateUV<M>(hit,g,subgrid);
-            if (epilog(hit.valid,hit))
-              return true;
-          }
-          return false;
-        }
-      };
-
-#if defined (__AVX__)
-
-    /*! Intersects 4 quads with 1 ray using AVX */
-    template<bool filter>
-      struct SubGridQuadMIntersector1MoellerTrumbore<4,filter>
-    {
-      __forceinline SubGridQuadMIntersector1MoellerTrumbore() {}
-
-      __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
-      
-      template<typename Epilog>
-        __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid, const Epilog& epilog) const
-      {
-        const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
-#if !defined(EMBREE_BACKFACE_CULLING)
-        const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
-        const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));        
-#else
-        const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
-        const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
-#endif
-        MoellerTrumboreHitM<8> hit;
-        MoellerTrumboreIntersector1<8> intersector(ray,nullptr);
-        const vbool8 flags(0,0,0,0,1,1,1,1);
-        if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,hit)))
-        {
-          vfloat8 U = hit.U, V = hit.V, absDen = hit.absDen;
-
-#if !defined(EMBREE_BACKFACE_CULLING)
-          hit.U = select(flags,absDen-V,U);
-          hit.V = select(flags,absDen-U,V);
-          hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f)); 
-#else
-          hit.U = select(flags,absDen-U,U);
-          hit.V = select(flags,absDen-V,V);
-#endif
-          /* correct U,V interpolation across the entire grid */
-          const vint8 sx((int)subgrid.x());
-          const vint8 sy((int)subgrid.y());
-          const vint8 sx8(sx + vint8(0,1,1,0,0,1,1,0));
-          const vint8 sy8(sy + vint8(0,0,1,1,0,0,1,1));
-          const float inv_resX = rcp((float)((int)g.resX-1));
-          const float inv_resY = rcp((float)((int)g.resY-1));          
-          hit.U = (hit.U + (vfloat8)sx8 * absDen) * inv_resX;
-          hit.V = (hit.V + (vfloat8)sy8 * absDen) * inv_resY;          
-
-          if (unlikely(epilog(hit.valid,hit)))
-            return true;
-        }
-        return false;
-      }
-      
-      __forceinline bool intersect(RayHit& ray, IntersectContext* context,
-                                   const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, 
-                                   const GridMesh::Grid &g, const SubGrid& subgrid) const
-      {
-          return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
-      }
-      
-      __forceinline bool occluded(Ray& ray, IntersectContext* context,
-                                  const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, 
-                                  const GridMesh::Grid &g, const SubGrid& subgrid) const
-      {
-          return intersect(ray,v0,v1,v2,v3,g,subgrid,Occluded1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
-      }
-    };
-
-#endif
-
-    // ============================================================================================================================
-    // ============================================================================================================================
-    // ============================================================================================================================
-
-
-    /* ----------------------------- */
-    /* -- ray packet intersectors -- */
-    /* ----------------------------- */
-
-    template<int K>
-      struct SubGridQuadHitK
-      {
-        __forceinline SubGridQuadHitK(const vfloat<K>& U,
-                                      const vfloat<K>& V,
-                                      const vfloat<K>& T,
-                                      const vfloat<K>& absDen,
-                                      const Vec3vf<K>& Ng,
-                                      const vbool<K>& flags,
-                                      const GridMesh::Grid &g, 
-                                      const SubGrid& subgrid,
-                                      const unsigned int i)
-        : U(U), V(V), T(T), absDen(absDen), flags(flags), tri_Ng(Ng), g(g), subgrid(subgrid), i(i) {}
-
-        __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
-        {
-          const vfloat<K> rcpAbsDen = rcp(absDen);
-          const vfloat<K> t = T * rcpAbsDen;
-          const vfloat<K> u0 = min(U * rcpAbsDen,1.0f);
-          const vfloat<K> v0 = min(V * rcpAbsDen,1.0f);
-          const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
-          const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
-          const vfloat<K> uu = select(flags,u1,u0);
-          const vfloat<K> vv = select(flags,v1,v0);
-          const unsigned int sx = subgrid.x() + (unsigned int)(i % 2);
-          const unsigned int sy = subgrid.y() + (unsigned int)(i >>1);
-          const float inv_resX = rcp((float)(int)(g.resX-1));
-          const float inv_resY = rcp((float)(int)(g.resY-1));
-          const vfloat<K> u = (uu + (float)(int)sx) * inv_resX;
-          const vfloat<K> v = (vv + (float)(int)sy) * inv_resY;
-          const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
-          return std::make_tuple(u,v,t,Ng);
-        }
-
-      private:
-        const vfloat<K> U;
-        const vfloat<K> V;
-        const vfloat<K> T;
-        const vfloat<K> absDen;
-        const vbool<K> flags;
-        const Vec3vf<K> tri_Ng;
-
-        const GridMesh::Grid &g;
-        const SubGrid& subgrid;
-        const size_t i;
-      };
-
-    template<int M, int K, bool filter>
-      struct SubGridQuadMIntersectorKMoellerTrumboreBase
-      {
-        __forceinline SubGridQuadMIntersectorKMoellerTrumboreBase(const vbool<K>& valid, const RayK<K>& ray) {}
-            
-        template<typename Epilog>
-        __forceinline vbool<K> intersectK(const vbool<K>& valid0,
-                                          RayK<K>& ray,
-                                          const Vec3vf<K>& tri_v0,
-                                          const Vec3vf<K>& tri_e1,
-                                          const Vec3vf<K>& tri_e2,
-                                          const Vec3vf<K>& tri_Ng,
-                                          const vbool<K>& flags,
-                                          const GridMesh::Grid &g, 
-                                          const SubGrid &subgrid,
-                                          const unsigned int i,
-                                          const Epilog& epilog) const
-        { 
-          /* calculate denominator */
-          vbool<K> valid = valid0;
-          const Vec3vf<K> C = tri_v0 - ray.org;
-          const Vec3vf<K> R = cross(C,ray.dir);
-          const vfloat<K> den = dot(tri_Ng,ray.dir);
-          const vfloat<K> absDen = abs(den);
-          const vfloat<K> sgnDen = signmsk(den);
-        
-          /* test against edge p2 p0 */
-          const vfloat<K> U = dot(R,tri_e2) ^ sgnDen;
-          valid &= U >= 0.0f;
-          if (likely(none(valid))) return false;
-        
-          /* test against edge p0 p1 */
-          const vfloat<K> V = dot(R,tri_e1) ^ sgnDen;
-          valid &= V >= 0.0f;
-          if (likely(none(valid))) return false;
-        
-          /* test against edge p1 p2 */
-          const vfloat<K> W = absDen-U-V;
-          valid &= W >= 0.0f;
-          if (likely(none(valid))) return false;
-        
-          /* perform depth test */
-          const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
-          valid &= (absDen*ray.tnear() < T) & (T <= absDen*ray.tfar);
-          if (unlikely(none(valid))) return false;
-        
-          /* perform backface culling */
-#if defined(EMBREE_BACKFACE_CULLING)
-          valid &= den < vfloat<K>(zero);
-          if (unlikely(none(valid))) return false;
-#else
-          valid &= den != vfloat<K>(zero);
-          if (unlikely(none(valid))) return false;
-#endif
-        
-          /* calculate hit information */
-          SubGridQuadHitK<K> hit(U,V,T,absDen,tri_Ng,flags,g,subgrid,i);
-          return epilog(valid,hit);
-        }
-      
-        template<typename Epilog>
-        __forceinline vbool<K> intersectK(const vbool<K>& valid0, 
-                                          RayK<K>& ray,
-                                          const Vec3vf<K>& tri_v0,
-                                          const Vec3vf<K>& tri_v1,
-                                          const Vec3vf<K>& tri_v2,
-                                          const vbool<K>& flags,
-                                          const GridMesh::Grid &g, 
-                                          const SubGrid &subgrid,
-                                          const unsigned int i,
-                                          const Epilog& epilog) const
-        {
-          const Vec3vf<K> e1 = tri_v0-tri_v1;
-          const Vec3vf<K> e2 = tri_v2-tri_v0;
-          const Vec3vf<K> Ng = cross(e2,e1);
-          return intersectK(valid0,ray,tri_v0,e1,e2,Ng,flags,g,subgrid,i,epilog);
-        }
-
-        template<typename Epilog>
-        __forceinline bool intersectK(const vbool<K>& valid0, 
-                                      RayK<K>& ray,
-                                      const Vec3vf<K>& v0,
-                                      const Vec3vf<K>& v1,
-                                      const Vec3vf<K>& v2,
-                                      const Vec3vf<K>& v3,
-                                      const GridMesh::Grid &g, 
-                                      const SubGrid &subgrid,
-                                      const unsigned int i,
-                                      const Epilog& epilog) const
-        {
-          intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),g,subgrid,i,epilog);
-          if (none(valid0)) return true;
-          intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),g,subgrid,i,epilog);
-          return none(valid0);
-        }
-
-        static  __forceinline bool intersect1(RayK<K>& ray,
-                                              size_t k,
-                                              const Vec3vf<M>& tri_v0,
-                                              const Vec3vf<M>& tri_e1,
-                                              const Vec3vf<M>& tri_e2,
-                                              const Vec3vf<M>& tri_Ng,
-                                              MoellerTrumboreHitM<M> &hit)
-        {
-          /* calculate denominator */
-          const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
-          const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
-          const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O;
-          const Vec3vf<M> R = cross(C,D);
-          const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D);
-          const vfloat<M> absDen = abs(den);
-          const vfloat<M> sgnDen = signmsk(den);
-        
-          /* perform edge tests */
-          const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen;
-          const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen;
-        
-          /* perform backface culling */
-#if defined(EMBREE_BACKFACE_CULLING)
-          vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
-#else
-          vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
-#endif
-          if (likely(none(valid))) return false;
-        
-          /* perform depth test */
-          const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
-          valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
-          if (likely(none(valid))) return false;
-        
-          /* calculate hit information */
-          new (&hit) MoellerTrumboreHitM<M>(valid,U,V,T,absDen,tri_Ng);
-          return true;
-        }
-
-        static __forceinline bool intersect1(RayK<K>& ray,
-                                             size_t k,
-                                             const Vec3vf<M>& v0,
-                                             const Vec3vf<M>& v1,
-                                             const Vec3vf<M>& v2,
-                                             MoellerTrumboreHitM<M> &hit)
-        {
-          const Vec3vf<M> e1 = v0-v1;
-          const Vec3vf<M> e2 = v2-v0;
-          const Vec3vf<M> Ng = cross(e2,e1);
-          return intersect1(ray,k,v0,e1,e2,Ng,hit);
-        }
-
-      };
-
-    template<int M, int K, bool filter>
-      struct SubGridQuadMIntersectorKMoellerTrumbore : public SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>
-    {
-      __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
-        : SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {}
-
-      __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
-                                    const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
-      {
-        Intersect1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
-
-        MoellerTrumboreHitM<4> hit;
-        if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,hit))
-        {
-          interpolateUV<M>(hit,g,subgrid);
-          epilog(hit.valid,hit);
-        }
-
-        if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,hit))
-        {
-          hit.U = hit.absDen - hit.U;
-          hit.V = hit.absDen - hit.V;
-          interpolateUV<M>(hit,g,subgrid);
-          epilog(hit.valid,hit);
-        }
-
-      }
-      
-      __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
-                                   const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
-      {
-        Occluded1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
-
-        MoellerTrumboreHitM<4> hit;
-        if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,hit))
-        {
-          interpolateUV<M>(hit,g,subgrid);
-          if (epilog(hit.valid,hit)) return true;
-        }
-
-        if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,hit))
-        {
-          hit.U = hit.absDen - hit.U;
-          hit.V = hit.absDen - hit.V;
-          interpolateUV<M>(hit,g,subgrid);
-          if (epilog(hit.valid,hit)) return true;
-        }
-        return false;
-      }
-    };
-
-
-#if defined (__AVX__)
-
-    /*! Intersects 4 quads with 1 ray using AVX */
-    template<int K, bool filter>
-      struct SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> : public SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>
-    {
-      __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
-        : SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>(valid,ray) {}
-      
-      template<typename Epilog>
-        __forceinline bool intersect1(RayK<K>& ray, size_t k,const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, 
-                                      const GridMesh::Grid &g, const SubGrid &subgrid, const Epilog& epilog) const
-      {
-        const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
-#if !defined(EMBREE_BACKFACE_CULLING)
-        const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
-        const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
-#else
-        const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
-        const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
-#endif
-        const vbool8 flags(0,0,0,0,1,1,1,1);
-
-        MoellerTrumboreHitM<8> hit;
-        if (SubGridQuadMIntersectorKMoellerTrumboreBase<8,K,filter>::intersect1(ray,k,vtx0,vtx1,vtx2,hit))
-        {
-          vfloat8 U = hit.U, V = hit.V, absDen = hit.absDen;
-#if !defined(EMBREE_BACKFACE_CULLING)
-          hit.U = select(flags,absDen-V,U);
-          hit.V = select(flags,absDen-U,V);
-          hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f)); 
-#else
-          hit.U = select(flags,absDen-U,U);
-          hit.V = select(flags,absDen-V,V);
-#endif
-
-          /* correct U,V interpolation across the entire grid */
-          const vint8 sx((int)subgrid.x());
-          const vint8 sy((int)subgrid.y());
-          const vint8 sx8(sx + vint8(0,1,1,0,0,1,1,0));
-          const vint8 sy8(sy + vint8(0,0,1,1,0,0,1,1));
-          const float inv_resX = rcp((float)((int)g.resX-1));
-          const float inv_resY = rcp((float)((int)g.resY-1));          
-          hit.U = (hit.U + (vfloat8)sx8 * absDen) * inv_resX;
-          hit.V = (hit.V + (vfloat8)sy8 * absDen) * inv_resY;          
-          if (unlikely(epilog(hit.valid,hit)))
-            return true;
-
-        }
-        return false;
-      }
-      
-      __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
-                                    const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
-      {
-        return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Intersect1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
-      }
-      
-      __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
-                                   const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
-      {
-        return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Occluded1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
-      }
-    };
-
-#endif
-
-
-
-  }
-}

+ 0 - 508
thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_pluecker.h

@@ -1,508 +0,0 @@
-// Copyright 2009-2020 Intel Corporation
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include "subgrid.h"
-#include "quad_intersector_moeller.h"
-#include "quad_intersector_pluecker.h"
-
-namespace embree
-{
-  namespace isa
-  {
-
-    template<int M>
-    struct SubGridQuadHitPlueckerM
-    {
-      __forceinline SubGridQuadHitPlueckerM() {}
-
-      __forceinline SubGridQuadHitPlueckerM(const vbool<M>& valid,
-                                            const vfloat<M>& U,
-                                            const vfloat<M>& V,
-                                            const vfloat<M>& UVW,
-                                            const vfloat<M>& t,
-                                            const Vec3vf<M>& Ng,
-                                            const vbool<M>& flags) : valid(valid), vt(t)
-      {
-        const vbool<M> invalid = abs(UVW) < min_rcp_input;
-        const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
-        const vfloat<M> u = min(U * rcpUVW,1.0f);
-        const vfloat<M> v = min(V * rcpUVW,1.0f);
-        const vfloat<M> u1 = vfloat<M>(1.0f) - u;
-        const vfloat<M> v1 = vfloat<M>(1.0f) - v;
-#if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
-        vu = select(flags,u1,u);
-        vv = select(flags,v1,v);
-        vNg = Vec3vf<M>(Ng.x,Ng.y,Ng.z);
-#else
-        const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
-        vv = select(flags,u1,v);
-        vu = select(flags,v1,u);
-        vNg = Vec3vf<M>(flip*Ng.x,flip*Ng.y,flip*Ng.z);
-#endif
-      }
-
-      __forceinline void finalize()
-      {
-      }
-
-      __forceinline Vec2f uv(const size_t i)
-      {
-        const float u = vu[i];
-        const float v = vv[i];
-        return Vec2f(u,v);
-      }
-
-      __forceinline float   t(const size_t i) { return vt[i]; }
-      __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
-
-    public:
-      vbool<M> valid;
-      vfloat<M> vu;
-      vfloat<M> vv;
-      vfloat<M> vt;
-      Vec3vf<M> vNg;
-    };
-
-    template<int M>
-      __forceinline void interpolateUV(SubGridQuadHitPlueckerM<M> &hit,const GridMesh::Grid &g, const SubGrid& subgrid, const vint<M> &stepX, const vint<M> &stepY) 
-    {
-      /* correct U,V interpolation across the entire grid */
-      const vint<M> sx((int)subgrid.x());
-      const vint<M> sy((int)subgrid.y());
-      const vint<M> sxM(sx + stepX);
-      const vint<M> syM(sy + stepY);
-      const float inv_resX = rcp((float)((int)g.resX-1));
-      const float inv_resY = rcp((float)((int)g.resY-1));          
-      hit.vu = (hit.vu + vfloat<M>(sxM)) * inv_resX;
-      hit.vv = (hit.vv + vfloat<M>(syM)) * inv_resY;
-    }
-
-    template<int M>
-    __forceinline static bool intersectPluecker(Ray& ray,
-                                                const Vec3vf<M>& tri_v0,
-                                                const Vec3vf<M>& tri_v1,
-                                                const Vec3vf<M>& tri_v2,
-                                                const vbool<M>& flags,
-                                                SubGridQuadHitPlueckerM<M> &hit)
-    {
-        /* calculate vertices relative to ray origin */
-      const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
-      const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
-        const Vec3vf<M> v0 = tri_v0-O;
-        const Vec3vf<M> v1 = tri_v1-O;
-        const Vec3vf<M> v2 = tri_v2-O;
-
-        /* calculate triangle edges */
-        const Vec3vf<M> e0 = v2-v0;
-        const Vec3vf<M> e1 = v0-v1;
-        const Vec3vf<M> e2 = v1-v2;
-
-        /* perform edge tests */
-        const vfloat<M> U = dot(cross(e0,v2+v0),D);
-        const vfloat<M> V = dot(cross(e1,v0+v1),D);
-        const vfloat<M> W = dot(cross(e2,v1+v2),D);
-        const vfloat<M> UVW = U+V+W;
-        const vfloat<M> eps = float(ulp)*abs(UVW);
-#if defined(EMBREE_BACKFACE_CULLING)
-        vbool<M> valid = max(U,V,W) <= eps;
-#else
-        vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
-#endif
-        if (unlikely(none(valid))) return false;
-
-        /* calculate geometry normal and denominator */
-        const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
-        const vfloat<M> den = twice(dot(Ng,D));
-
-        /* perform depth test */
-        const vfloat<M> T = twice(dot(v0,Ng));
-        const vfloat<M> t = rcp(den)*T;
-        valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
-        valid &= den != vfloat<M>(zero);
-        if (unlikely(none(valid))) return false;
-
-        /* update hit information */
-        new (&hit) SubGridQuadHitPlueckerM<M>(valid,U,V,UVW,t,Ng,flags);
-        return true;
-      }
-
-    template<int M, bool filter>
-      struct SubGridQuadMIntersector1Pluecker;
-
-    template<int M, bool filter>
-      struct SubGridQuadMIntersector1Pluecker
-      {
-        __forceinline SubGridQuadMIntersector1Pluecker() {}
-
-        __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
-
-        __forceinline void intersect(RayHit& ray, IntersectContext* context,
-                                     const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
-                                     const GridMesh::Grid &g, const SubGrid& subgrid) const
-        {
-          SubGridQuadHitPlueckerM<M> hit;
-          Intersect1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
-
-          /* intersect first triangle */
-          if (intersectPluecker(ray,v0,v1,v3,vbool<M>(false),hit)) 
-          {
-            interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-            epilog(hit.valid,hit);
-          }
-
-          /* intersect second triangle */
-          if (intersectPluecker(ray,v2,v3,v1,vbool<M>(true),hit)) 
-          {
-            interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-            epilog(hit.valid,hit);
-          }
-        }
-      
-        __forceinline bool occluded(Ray& ray, IntersectContext* context,
-                                    const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
-                                    const GridMesh::Grid &g, const SubGrid& subgrid) const
-        {
-          SubGridQuadHitPlueckerM<M> hit;
-          Occluded1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
-          
-          /* intersect first triangle */
-          if (intersectPluecker(ray,v0,v1,v3,vbool<M>(false),hit)) 
-          {
-            interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-            if (epilog(hit.valid,hit))
-              return true;
-          }
-
-          /* intersect second triangle */
-          if (intersectPluecker(ray,v2,v3,v1,vbool<M>(true),hit)) 
-          {
-            interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-            if (epilog(hit.valid,hit))
-              return true;
-          }
-
-          return false;
-        }
-      };
-
-#if defined (__AVX__)
-
-    /*! Intersects 4 quads with 1 ray using AVX */
-    template<bool filter>
-      struct SubGridQuadMIntersector1Pluecker<4,filter>
-    {
-      __forceinline SubGridQuadMIntersector1Pluecker() {}
-
-      __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
-      
-      template<typename Epilog>
-        __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid, const Epilog& epilog) const
-      {
-        const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
-#if !defined(EMBREE_BACKFACE_CULLING)
-        const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
-        const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));        
-#else
-        const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
-        const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
-#endif
-        SubGridQuadHitPlueckerM<8> hit;
-        const vbool8 flags(0,0,0,0,1,1,1,1);
-        if (unlikely(intersectPluecker(ray,vtx0,vtx1,vtx2,flags,hit)))
-        {
-          /* correct U,V interpolation across the entire grid */
-          interpolateUV<8>(hit,g,subgrid,vint<8>(0,1,1,0,0,1,1,0),vint<8>(0,0,1,1,0,0,1,1));            
-          if (unlikely(epilog(hit.valid,hit)))
-            return true;
-        }
-        return false;
-      }
-      
-      __forceinline bool intersect(RayHit& ray, IntersectContext* context,
-                                   const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, 
-                                   const GridMesh::Grid &g, const SubGrid& subgrid) const
-      {
-          return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
-      }
-      
-      __forceinline bool occluded(Ray& ray, IntersectContext* context,
-                                  const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, 
-                                  const GridMesh::Grid &g, const SubGrid& subgrid) const
-      {
-          return intersect(ray,v0,v1,v2,v3,g,subgrid,Occluded1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
-      }
-    };
-
-#endif
-
-
-    /* ----------------------------- */
-    /* -- ray packet intersectors -- */
-    /* ----------------------------- */
-
-    template<int K>
-      struct SubGridQuadHitPlueckerK
-      {
-         __forceinline SubGridQuadHitPlueckerK(const vfloat<K>& U,
-                                               const vfloat<K>& V,
-                                               const vfloat<K>& UVW,
-                                               const vfloat<K>& t,
-                                               const Vec3vf<K>& Ng,
-                                               const vbool<K>& flags,
-                                               const GridMesh::Grid &g, 
-                                               const SubGrid& subgrid,
-                                               const unsigned int i)
-         : U(U), V(V), UVW(UVW), t(t), flags(flags), tri_Ng(Ng), g(g), subgrid(subgrid), i(i) {}
-
-        __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
-        {
-          const vbool<K> invalid = abs(UVW) < min_rcp_input;
-          const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
-          const vfloat<K> u0 = min(U * rcpUVW,1.0f);
-          const vfloat<K> v0 = min(V * rcpUVW,1.0f);
-          const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
-          const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
-          const vfloat<K> uu = select(flags,u1,u0);
-          const vfloat<K> vv = select(flags,v1,v0);
-          const unsigned int sx = subgrid.x() + (unsigned int)(i % 2);
-          const unsigned int sy = subgrid.y() + (unsigned int)(i >>1);
-          const float inv_resX = rcp((float)(int)(g.resX-1));
-          const float inv_resY = rcp((float)(int)(g.resY-1));
-          const vfloat<K> u = (uu + (float)(int)sx) * inv_resX;
-          const vfloat<K> v = (vv + (float)(int)sy) * inv_resY;
-          const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
-          return std::make_tuple(u,v,t,Ng);
-        }
-
-      private:
-        const vfloat<K> U;
-        const vfloat<K> V;
-        const vfloat<K> UVW;
-        const vfloat<K> t;
-        const vfloat<K> absDen;
-        const vbool<K> flags;
-        const Vec3vf<K> tri_Ng;
-
-        const GridMesh::Grid &g;
-        const SubGrid& subgrid;
-        const size_t i;
-      };
-
-
-    template<int M, int K, bool filter>
-      struct SubGridQuadMIntersectorKPlueckerBase
-      {
-        __forceinline SubGridQuadMIntersectorKPlueckerBase(const vbool<K>& valid, const RayK<K>& ray) {}
-            
-        template<typename Epilog>
-        __forceinline vbool<K> intersectK(const vbool<K>& valid0,
-                                          RayK<K>& ray,
-                                          const Vec3vf<K>& tri_v0,
-                                          const Vec3vf<K>& tri_v1,
-                                          const Vec3vf<K>& tri_v2,
-                                          const Vec3vf<K>& tri_Ng,
-                                          const vbool<K>& flags,
-                                          const GridMesh::Grid &g, 
-                                          const SubGrid &subgrid,
-                                          const unsigned int i,
-                                          const Epilog& epilog) const
-        { 
-          /* calculate denominator */
-        /* calculate vertices relative to ray origin */
-          vbool<K> valid = valid0;
-          const Vec3vf<K> O = ray.org;
-          const Vec3vf<K> D = ray.dir;
-          const Vec3vf<K> v0 = tri_v0-O;
-          const Vec3vf<K> v1 = tri_v1-O;
-          const Vec3vf<K> v2 = tri_v2-O;
-          
-          /* calculate triangle edges */
-          const Vec3vf<K> e0 = v2-v0;
-          const Vec3vf<K> e1 = v0-v1;
-          const Vec3vf<K> e2 = v1-v2;
-           
-          /* perform edge tests */
-          const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
-          const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
-          const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
-          const vfloat<K> UVW = U+V+W;
-          const vfloat<K> eps = float(ulp)*abs(UVW);
-#if defined(EMBREE_BACKFACE_CULLING)
-          valid &= max(U,V,W) <= eps;
-#else
-          valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
-#endif
-          if (unlikely(none(valid))) return false;
-          
-          /* calculate geometry normal and denominator */
-          const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
-          const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
-
-          /* perform depth test */
-          const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
-          const vfloat<K> t = rcp(den)*T;
-          valid &= ray.tnear() <= t & t <= ray.tfar;
-          valid &= den != vfloat<K>(zero);
-          if (unlikely(none(valid))) return false;
-          
-          /* calculate hit information */
-          SubGridQuadHitPlueckerK<K> hit(U,V,UVW,t,tri_Ng,flags,g,subgrid,i);
-          return epilog(valid,hit);
-        }
-      
-        template<typename Epilog>
-        __forceinline vbool<K> intersectK(const vbool<K>& valid0, 
-                                          RayK<K>& ray,
-                                          const Vec3vf<K>& v0,
-                                          const Vec3vf<K>& v1,
-                                          const Vec3vf<K>& v2,
-                                          const vbool<K>& flags,
-                                          const GridMesh::Grid &g, 
-                                          const SubGrid &subgrid,
-                                          const unsigned int i,
-                                          const Epilog& epilog) const
-        {
-          const Vec3vf<K> e1 = v0-v1;
-          const Vec3vf<K> e2 = v2-v0;
-          const Vec3vf<K> Ng = cross(e2,e1);
-          return intersectK(valid0,ray,v0,v1,v2,Ng,flags,g,subgrid,i,epilog);
-        }
-
-        template<typename Epilog>
-        __forceinline bool intersectK(const vbool<K>& valid0, 
-                                      RayK<K>& ray,
-                                      const Vec3vf<K>& v0,
-                                      const Vec3vf<K>& v1,
-                                      const Vec3vf<K>& v2,
-                                      const Vec3vf<K>& v3,
-                                      const GridMesh::Grid &g, 
-                                      const SubGrid &subgrid,
-                                      const unsigned int i,
-                                      const Epilog& epilog) const
-        {
-          intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),g,subgrid,i,epilog);
-          if (none(valid0)) return true;
-          intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),g,subgrid,i,epilog);
-          return none(valid0);
-        }
-
-        static  __forceinline bool intersect1(RayK<K>& ray,
-                                              size_t k,
-                                              const Vec3vf<M>& tri_v0,
-                                              const Vec3vf<M>& tri_v1,
-                                              const Vec3vf<M>& tri_v2,
-                                              const Vec3vf<M>& tri_Ng,
-                                              const vbool<M>& flags,
-                                              SubGridQuadHitPlueckerM<M> &hit)
-        {
-          /* calculate vertices relative to ray origin */
-          const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
-          const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
-          const Vec3vf<M> v0 = tri_v0-O;
-          const Vec3vf<M> v1 = tri_v1-O;
-          const Vec3vf<M> v2 = tri_v2-O;
-          
-          /* calculate triangle edges */
-          const Vec3vf<M> e0 = v2-v0;
-          const Vec3vf<M> e1 = v0-v1;
-          const Vec3vf<M> e2 = v1-v2;
-          
-          /* perform edge tests */
-          const vfloat<M> U = dot(cross(e0,v2+v0),D);
-          const vfloat<M> V = dot(cross(e1,v0+v1),D);
-          const vfloat<M> W = dot(cross(e2,v1+v2),D);
-          const vfloat<M> UVW = U+V+W;
-          const vfloat<M> eps = float(ulp)*abs(UVW);
-#if defined(EMBREE_BACKFACE_CULLING)
-          vbool<M> valid = max(U,V,W) <= eps ;
-#else
-          vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
-#endif
-          if (unlikely(none(valid))) return false;
-          
-          /* calculate geometry normal and denominator */
-          const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
-          const vfloat<M> den = twice(dot(Ng,D));
-
-          /* perform depth test */
-          const vfloat<M> T = twice(dot(v0,Ng));
-          const vfloat<M> t = rcp(den)*T;
-          valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
-          if (unlikely(none(valid))) return false;
-          
-          /* avoid division by 0 */
-          valid &= den != vfloat<M>(zero);
-          if (unlikely(none(valid))) return false;
-          
-          /* update hit information */
-          new (&hit) SubGridQuadHitPlueckerM<M>(valid,U,V,UVW,t,tri_Ng,flags);
-          return true;
-        }
-
-        static __forceinline bool intersect1(RayK<K>& ray,
-                                             size_t k,
-                                             const Vec3vf<M>& v0,
-                                             const Vec3vf<M>& v1,
-                                             const Vec3vf<M>& v2,
-                                             const vbool<M>& flags,
-                                             SubGridQuadHitPlueckerM<M> &hit)
-        {
-          const Vec3vf<M> e1 = v0-v1;
-          const Vec3vf<M> e2 = v2-v0;
-          const Vec3vf<M> Ng = cross(e2,e1); // FIXME: optimize!!!
-          return intersect1(ray,k,v0,v1,v2,Ng,flags,hit);
-        }
-
-      };
-
-    template<int M, int K, bool filter>
-      struct SubGridQuadMIntersectorKPluecker : public SubGridQuadMIntersectorKPlueckerBase<M,K,filter>
-    {
-      __forceinline SubGridQuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
-        : SubGridQuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {}
-
-      __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
-                                    const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
-      {
-        Intersect1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
-
-        SubGridQuadHitPlueckerM<4> hit;
-        if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,vboolf4(false),hit))
-        {
-          interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-          epilog(hit.valid,hit);
-        }
-
-        if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,vboolf4(true),hit))
-        {
-          interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-          epilog(hit.valid,hit);
-        }
-
-      }
-      
-      __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
-                                   const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
-      {
-        Occluded1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
-
-        SubGridQuadHitPlueckerM<4> hit;
-        if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,vboolf4(false),hit))
-        {
-          interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-          if (epilog(hit.valid,hit)) return true;
-        }
-
-        if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,vboolf4(true),hit))
-        {
-          interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
-          if (epilog(hit.valid,hit)) return true;
-        }
-        return false;
-      }
-    };
-
-  }
-}

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_any_of.h → thirdparty/embree/common/algorithms/parallel_any_of.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_filter.h → thirdparty/embree/common/algorithms/parallel_filter.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 15 - 58
thirdparty/embree-aarch64/common/algorithms/parallel_for.h → thirdparty/embree/common/algorithms/parallel_for.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -8,12 +8,6 @@
 #include "../math/math.h"
 #include "../math/math.h"
 #include "../math/range.h"
 #include "../math/range.h"
 
 
-#if defined(TASKING_GCD) && defined(BUILD_IOS)
-#include <dispatch/dispatch.h>
-#include <algorithm>
-#include <type_traits>
-#endif
-
 namespace embree
 namespace embree
 {
 {
   /* parallel_for without range */
   /* parallel_for without range */
@@ -29,28 +23,10 @@ namespace embree
       if (!TaskScheduler::wait())
       if (!TaskScheduler::wait())
         // -- GODOT start --
         // -- GODOT start --
         // throw std::runtime_error("task cancelled");
         // throw std::runtime_error("task cancelled");
-        abort(); 
+        abort();
         // -- GODOT end --
         // -- GODOT end --
     }
     }
-#elif defined(TASKING_GCD) && defined(BUILD_IOS)
-      
-    const size_t baselineNumBlocks = (TaskScheduler::threadCount() > 1)? TaskScheduler::threadCount() : 1;
-    const size_t length = N;
-    const size_t blockSize = (length + baselineNumBlocks-1) / baselineNumBlocks;
-    const size_t numBlocks = (length + blockSize-1) / blockSize;
-      
-    dispatch_apply(numBlocks, DISPATCH_APPLY_AUTO, ^(size_t currentBlock) {
-          
-        const size_t start = (currentBlock * blockSize);
-        const size_t blockLength = std::min(length - start, blockSize);
-        const size_t end = start + blockLength;
-          
-        for(size_t i=start; i < end; i++)
-        {
-            func(i);
-        }
-    });
-      
+    
 #elif defined(TASKING_TBB)
 #elif defined(TASKING_TBB)
   #if TBB_INTERFACE_VERSION >= 12002
   #if TBB_INTERFACE_VERSION >= 12002
     tbb::task_group_context context;
     tbb::task_group_context context;
@@ -60,7 +36,7 @@ namespace embree
     if (context.is_group_execution_cancelled())
     if (context.is_group_execution_cancelled())
       // -- GODOT start --
       // -- GODOT start --
       // throw std::runtime_error("task cancelled");
       // throw std::runtime_error("task cancelled");
-      abort(); 
+      abort();
       // -- GODOT end --
       // -- GODOT end --
   #else
   #else
     tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
     tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
@@ -69,7 +45,7 @@ namespace embree
     if (tbb::task::self().is_cancelled())
     if (tbb::task::self().is_cancelled())
       // -- GODOT start --
       // -- GODOT start --
       // throw std::runtime_error("task cancelled");
       // throw std::runtime_error("task cancelled");
-      abort(); 
+      abort();
       // -- GODOT end --
       // -- GODOT end --
   #endif
   #endif
 
 
@@ -92,28 +68,9 @@ namespace embree
     if (!TaskScheduler::wait())
     if (!TaskScheduler::wait())
       // -- GODOT start --
       // -- GODOT start --
       // throw std::runtime_error("task cancelled");
       // throw std::runtime_error("task cancelled");
-      abort(); 
+      abort();
       // -- GODOT end --
       // -- GODOT end --
 
 
-#elif defined(TASKING_GCD) && defined(BUILD_IOS)
-      
-    const size_t baselineNumBlocks = (TaskScheduler::threadCount() > 1)? 4*TaskScheduler::threadCount() : 1;
-    const size_t length = last - first;
-    const size_t blockSizeByThreads = (length + baselineNumBlocks-1) / baselineNumBlocks;
-    size_t blockSize = std::max<size_t>(minStepSize,blockSizeByThreads);
-    blockSize += blockSize % 4;
-      
-    const size_t numBlocks = (length + blockSize-1) / blockSize;
-      
-    dispatch_apply(numBlocks, DISPATCH_APPLY_AUTO, ^(size_t currentBlock) {
-          
-        const size_t start = first + (currentBlock * blockSize);
-        const size_t end = std::min<size_t>(last, start + blockSize);
-          
-        func( embree::range<Index>(start,end) );
-    });
-      
-
 #elif defined(TASKING_TBB)
 #elif defined(TASKING_TBB)
   #if TBB_INTERFACE_VERSION >= 12002
   #if TBB_INTERFACE_VERSION >= 12002
     tbb::task_group_context context;
     tbb::task_group_context context;
@@ -123,7 +80,7 @@ namespace embree
     if (context.is_group_execution_cancelled())
     if (context.is_group_execution_cancelled())
       // -- GODOT start --
       // -- GODOT start --
       // throw std::runtime_error("task cancelled");
       // throw std::runtime_error("task cancelled");
-      abort(); 
+      abort();
       // -- GODOT end --
       // -- GODOT end --
   #else
   #else
     tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
     tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
@@ -132,7 +89,7 @@ namespace embree
     if (tbb::task::self().is_cancelled())
     if (tbb::task::self().is_cancelled())
       // -- GODOT start --
       // -- GODOT start --
       // throw std::runtime_error("task cancelled");
       // throw std::runtime_error("task cancelled");
-      abort(); 
+      abort();
       // -- GODOT end --
       // -- GODOT end --
   #endif
   #endif
 
 
@@ -167,7 +124,7 @@ namespace embree
       if (context.is_group_execution_cancelled())
       if (context.is_group_execution_cancelled())
         // -- GODOT start --
         // -- GODOT start --
         // throw std::runtime_error("task cancelled");
         // throw std::runtime_error("task cancelled");
-        abort(); 
+        abort();
         // -- GODOT end --
         // -- GODOT end --
     #else
     #else
       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
@@ -176,7 +133,7 @@ namespace embree
       if (tbb::task::self().is_cancelled())
       if (tbb::task::self().is_cancelled())
         // -- GODOT start --
         // -- GODOT start --
         // throw std::runtime_error("task cancelled");
         // throw std::runtime_error("task cancelled");
-        abort(); 
+        abort();
         // -- GODOT end --
         // -- GODOT end --
     #endif
     #endif
   }
   }
@@ -192,10 +149,10 @@ namespace embree
           func(i);
           func(i);
         },ap,context);
         },ap,context);
       if (context.is_group_execution_cancelled())
       if (context.is_group_execution_cancelled())
-       // -- GODOT start --
-       // throw std::runtime_error("task cancelled");
-       abort(); 
-       // -- GODOT end --
+        // -- GODOT start --
+        // throw std::runtime_error("task cancelled");
+        abort();
+        // -- GODOT end --
     #else
     #else
       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
           func(i);
           func(i);
@@ -203,7 +160,7 @@ namespace embree
       if (tbb::task::self().is_cancelled())
       if (tbb::task::self().is_cancelled())
         // -- GODOT start --
         // -- GODOT start --
         // throw std::runtime_error("task cancelled");
         // throw std::runtime_error("task cancelled");
-        abort(); 
+        abort();
         // -- GODOT end --
         // -- GODOT end --
     #endif
     #endif
   }
   }

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_for_for.h → thirdparty/embree/common/algorithms/parallel_for_for.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.h → thirdparty/embree/common/algorithms/parallel_for_for_prefix_sum.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_map.h → thirdparty/embree/common/algorithms/parallel_map.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_partition.h → thirdparty/embree/common/algorithms/parallel_partition.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.h → thirdparty/embree/common/algorithms/parallel_prefix_sum.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 2 - 2
thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h → thirdparty/embree/common/algorithms/parallel_reduce.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -43,7 +43,7 @@ namespace embree
   template<typename Index, typename Value, typename Func, typename Reduction>
   template<typename Index, typename Value, typename Func, typename Reduction>
     __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
     __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
   {
   {
-#if defined(TASKING_INTERNAL) || (defined(TASKING_GCD) && defined(BUILD_IOS))
+#if defined(TASKING_INTERNAL)
 
 
     /* fast path for small number of iterations */
     /* fast path for small number of iterations */
     Index taskCount = (last-first+minStepSize-1)/minStepSize;
     Index taskCount = (last-first+minStepSize-1)/minStepSize;

+ 1 - 1
thirdparty/embree-aarch64/common/algorithms/parallel_set.h → thirdparty/embree/common/algorithms/parallel_set.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 3 - 6
thirdparty/embree-aarch64/common/algorithms/parallel_sort.h → thirdparty/embree/common/algorithms/parallel_sort.h

@@ -1,13 +1,10 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
 #include "../simd/simd.h"
 #include "../simd/simd.h"
 #include "parallel_for.h"
 #include "parallel_for.h"
-#if defined(TASKING_GCD) && defined(BUILD_IOS)
-#include "../sys/alloc.h"
-#endif
 #include <algorithm>
 #include <algorithm>
 
 
 namespace embree
 namespace embree
@@ -323,7 +320,7 @@ namespace embree
 #pragma nounroll      
 #pragma nounroll      
 #endif
 #endif
       for (size_t i=startID; i<endID; i++) {
       for (size_t i=startID; i<endID; i++) {
-#if defined(__X86_64__) || defined(__aarch64__)
+#if defined(__64BIT__)
         const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
         const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
 #else
 #else
         const Key index = ((Key)src[i] >> shift) & mask;
         const Key index = ((Key)src[i] >> shift) & mask;
@@ -385,7 +382,7 @@ namespace embree
 #endif
 #endif
       for (size_t i=startID; i<endID; i++) {
       for (size_t i=startID; i<endID; i++) {
         const Ty elt = src[i];
         const Ty elt = src[i];
-#if defined(__X86_64__) || defined(__aarch64__)
+#if defined(__64BIT__)
         const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
         const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
 #else
 #else
         const size_t index = ((Key)src[i] >> shift) & mask;
         const size_t index = ((Key)src[i] >> shift) & mask;

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/parsestream.h → thirdparty/embree/common/lexers/parsestream.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/stream.h → thirdparty/embree/common/lexers/stream.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/streamfilters.h → thirdparty/embree/common/lexers/streamfilters.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/stringstream.cpp → thirdparty/embree/common/lexers/stringstream.cpp

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #include "stringstream.h"
 #include "stringstream.h"

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/stringstream.h → thirdparty/embree/common/lexers/stringstream.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/tokenstream.cpp → thirdparty/embree/common/lexers/tokenstream.cpp

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #include "tokenstream.h"
 #include "tokenstream.h"

+ 1 - 1
thirdparty/embree-aarch64/common/lexers/tokenstream.h → thirdparty/embree/common/lexers/tokenstream.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/math/affinespace.h → thirdparty/embree/common/math/affinespace.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 4 - 4
thirdparty/embree-aarch64/common/math/bbox.h → thirdparty/embree/common/math/bbox.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -77,7 +77,7 @@ namespace embree
     return lower > upper;
     return lower > upper;
   }
   }
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
+#if defined(__SSE__)
   template<> __forceinline bool BBox<Vec3fa>::empty() const {
   template<> __forceinline bool BBox<Vec3fa>::empty() const {
     return !all(le_mask(lower,upper));
     return !all(le_mask(lower,upper));
   }
   }
@@ -228,11 +228,11 @@ namespace embree
 /// SSE / AVX / MIC specializations
 /// SSE / AVX / MIC specializations
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined (__SSE__) || defined(__ARM_NEON)
+#if defined __SSE__
 #include "../simd/sse.h"
 #include "../simd/sse.h"
 #endif
 #endif
 
 
-#if defined (__AVX__)
+#if defined __AVX__
 #include "../simd/avx.h"
 #include "../simd/avx.h"
 #endif
 #endif
 
 

+ 2 - 2
thirdparty/embree-aarch64/common/math/col3.h → thirdparty/embree/common/math/col3.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -42,6 +42,6 @@ namespace embree
   }
   }
 
 
   /*! default template instantiations */
   /*! default template instantiations */
-  typedef Col3<uint8_t      > Col3uc;
+  typedef Col3<unsigned char> Col3uc;
   typedef Col3<float        > Col3f;
   typedef Col3<float        > Col3f;
 }
 }

+ 2 - 2
thirdparty/embree-aarch64/common/math/col4.h → thirdparty/embree/common/math/col4.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -42,6 +42,6 @@ namespace embree
   }
   }
 
 
   /*! default template instantiations */
   /*! default template instantiations */
-  typedef Col4<uint8_t      > Col4uc;
+  typedef Col4<unsigned char> Col4uc;
   typedef Col4<float        > Col4f;
   typedef Col4<float        > Col4f;
 }
 }

+ 14 - 30
thirdparty/embree-aarch64/common/math/color.h → thirdparty/embree/common/math/color.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -52,17 +52,17 @@ namespace embree
     __forceinline void set(Col3uc& d) const 
     __forceinline void set(Col3uc& d) const 
     {
     {
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
-      d.r = (uint8_t)(s[0]); 
-      d.g = (uint8_t)(s[1]); 
-      d.b = (uint8_t)(s[2]); 
+      d.r = (unsigned char)(s[0]); 
+      d.g = (unsigned char)(s[1]); 
+      d.b = (unsigned char)(s[2]); 
     }
     }
     __forceinline void set(Col4uc& d) const 
     __forceinline void set(Col4uc& d) const 
     {
     {
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
-      d.r = (uint8_t)(s[0]); 
-      d.g = (uint8_t)(s[1]); 
-      d.b = (uint8_t)(s[2]); 
-      d.a = (uint8_t)(s[3]); 
+      d.r = (unsigned char)(s[0]); 
+      d.g = (unsigned char)(s[1]); 
+      d.b = (unsigned char)(s[2]); 
+      d.a = (unsigned char)(s[3]); 
     }
     }
 
 
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -114,16 +114,16 @@ namespace embree
     __forceinline void set(Col3uc& d) const 
     __forceinline void set(Col3uc& d) const 
     { 
     { 
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
-      d.r = (uint8_t)(s[0]); 
-      d.g = (uint8_t)(s[1]); 
-      d.b = (uint8_t)(s[2]); 
+      d.r = (unsigned char)(s[0]); 
+      d.g = (unsigned char)(s[1]); 
+      d.b = (unsigned char)(s[2]); 
     }
     }
     __forceinline void set(Col4uc& d) const 
     __forceinline void set(Col4uc& d) const 
     { 
     { 
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
       vfloat4 s = clamp(vfloat4(m128))*255.0f;
-      d.r = (uint8_t)(s[0]); 
-      d.g = (uint8_t)(s[1]); 
-      d.b = (uint8_t)(s[2]); 
+      d.r = (unsigned char)(s[0]); 
+      d.g = (unsigned char)(s[1]); 
+      d.b = (unsigned char)(s[2]); 
       d.a = 255; 
       d.a = 255; 
     }
     }
 
 
@@ -152,37 +152,21 @@ namespace embree
   }
   }
   __forceinline const Color rcp  ( const Color& a )
   __forceinline const Color rcp  ( const Color& a )
   {
   {
-#if defined(__aarch64__) && defined(BUILD_IOS)
-    __m128 reciprocal = _mm_rcp_ps(a.m128);
-    reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
-    reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
-    return (const Color)reciprocal;
-#else
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     const Color r = _mm_rcp14_ps(a.m128);
     const Color r = _mm_rcp14_ps(a.m128);
 #else
 #else
     const Color r = _mm_rcp_ps(a.m128);
     const Color r = _mm_rcp_ps(a.m128);
 #endif
 #endif
     return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
     return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
-#endif  //defined(__aarch64__) && defined(BUILD_IOS)
   }
   }
   __forceinline const Color rsqrt( const Color& a )
   __forceinline const Color rsqrt( const Color& a )
   {
   {
-#if defined(__aarch64__) && defined(BUILD_IOS)
-    __m128 r = _mm_rsqrt_ps(a.m128);
-    r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
-    r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
-    return r;
-#else
-      
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     __m128 r = _mm_rsqrt14_ps(a.m128);
     __m128 r = _mm_rsqrt14_ps(a.m128);
 #else
 #else
     __m128 r = _mm_rsqrt_ps(a.m128);
     __m128 r = _mm_rsqrt_ps(a.m128);
 #endif
 #endif
     return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
     return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
-      
-#endif  //defined(__aarch64__) && defined(BUILD_IOS)
   }
   }
   __forceinline const Color sqrt ( const Color& a ) { return _mm_sqrt_ps(a.m128); }
   __forceinline const Color sqrt ( const Color& a ) { return _mm_sqrt_ps(a.m128); }
 
 

+ 27 - 0
thirdparty/embree/common/math/constants.cpp

@@ -0,0 +1,27 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "constants.h"
+
+namespace embree
+{
+  TrueTy True;
+  FalseTy False;
+  ZeroTy zero;
+  OneTy one;
+  NegInfTy neg_inf;
+  PosInfTy inf;
+  PosInfTy pos_inf;
+  NaNTy nan;
+  UlpTy ulp;
+  PiTy pi;
+  OneOverPiTy one_over_pi;
+  TwoPiTy two_pi;
+  OneOverTwoPiTy one_over_two_pi;
+  FourPiTy four_pi;
+  OneOverFourPiTy one_over_four_pi;
+  StepTy step;
+  ReverseStepTy reverse_step;
+  EmptyTy empty;
+  UndefinedTy undefined;
+}

+ 9 - 51
thirdparty/embree-aarch64/common/math/constants.h → thirdparty/embree/common/math/constants.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -12,19 +12,6 @@
 #include <cfloat>
 #include <cfloat>
 #include <climits>
 #include <climits>
 
 
-// Math constants may not be defined in libcxx + mingw + strict C++ standard
-#if defined(__MINGW32__)
-
-// TODO(LTE): use constexpr
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-#ifndef M_1_PI
-#define M_1_PI 0.31830988618379067154
-#endif
-
-#endif // __MINGW32__
-
 namespace embree
 namespace embree
 {
 {
   static MAYBE_UNUSED const float one_over_255 = 1.0f/255.0f;
   static MAYBE_UNUSED const float one_over_255 = 1.0f/255.0f;
@@ -57,8 +44,8 @@ namespace embree
     __forceinline operator unsigned int      ( ) const { return 0; }
     __forceinline operator unsigned int      ( ) const { return 0; }
     __forceinline operator          short    ( ) const { return 0; }
     __forceinline operator          short    ( ) const { return 0; }
     __forceinline operator unsigned short    ( ) const { return 0; }
     __forceinline operator unsigned short    ( ) const { return 0; }
-    __forceinline operator          int8_t     ( ) const { return 0; }
-    __forceinline operator uint8_t     ( ) const { return 0; }
+    __forceinline operator          char     ( ) const { return 0; }
+    __forceinline operator unsigned char     ( ) const { return 0; }
   }; 
   }; 
 
 
   extern MAYBE_UNUSED ZeroTy zero;
   extern MAYBE_UNUSED ZeroTy zero;
@@ -75,8 +62,8 @@ namespace embree
     __forceinline operator unsigned int      ( ) const { return 1; }
     __forceinline operator unsigned int      ( ) const { return 1; }
     __forceinline operator          short    ( ) const { return 1; }
     __forceinline operator          short    ( ) const { return 1; }
     __forceinline operator unsigned short    ( ) const { return 1; }
     __forceinline operator unsigned short    ( ) const { return 1; }
-    __forceinline operator          int8_t     ( ) const { return 1; }
-    __forceinline operator uint8_t     ( ) const { return 1; }
+    __forceinline operator          char     ( ) const { return 1; }
+    __forceinline operator unsigned char     ( ) const { return 1; }
   };
   };
 
 
   extern MAYBE_UNUSED OneTy one;
   extern MAYBE_UNUSED OneTy one;
@@ -93,8 +80,8 @@ namespace embree
     __forceinline operator unsigned int      ( ) const { return std::numeric_limits<unsigned int>::min(); }
     __forceinline operator unsigned int      ( ) const { return std::numeric_limits<unsigned int>::min(); }
     __forceinline operator          short    ( ) const { return std::numeric_limits<short>::min(); }
     __forceinline operator          short    ( ) const { return std::numeric_limits<short>::min(); }
     __forceinline operator unsigned short    ( ) const { return std::numeric_limits<unsigned short>::min(); }
     __forceinline operator unsigned short    ( ) const { return std::numeric_limits<unsigned short>::min(); }
-    __forceinline operator          int8_t     ( ) const { return std::numeric_limits<int8_t>::min(); }
-    __forceinline operator uint8_t     ( ) const { return std::numeric_limits<uint8_t>::min(); }
+    __forceinline operator          char     ( ) const { return std::numeric_limits<char>::min(); }
+    __forceinline operator unsigned char     ( ) const { return std::numeric_limits<unsigned char>::min(); }
 
 
   };
   };
 
 
@@ -112,8 +99,8 @@ namespace embree
     __forceinline operator unsigned int      ( ) const { return std::numeric_limits<unsigned int>::max(); }
     __forceinline operator unsigned int      ( ) const { return std::numeric_limits<unsigned int>::max(); }
     __forceinline operator          short    ( ) const { return std::numeric_limits<short>::max(); }
     __forceinline operator          short    ( ) const { return std::numeric_limits<short>::max(); }
     __forceinline operator unsigned short    ( ) const { return std::numeric_limits<unsigned short>::max(); }
     __forceinline operator unsigned short    ( ) const { return std::numeric_limits<unsigned short>::max(); }
-    __forceinline operator          int8_t     ( ) const { return std::numeric_limits<int8_t>::max(); }
-    __forceinline operator uint8_t     ( ) const { return std::numeric_limits<uint8_t>::max(); }
+    __forceinline operator          char     ( ) const { return std::numeric_limits<char>::max(); }
+    __forceinline operator unsigned char     ( ) const { return std::numeric_limits<unsigned char>::max(); }
   };
   };
 
 
   extern MAYBE_UNUSED PosInfTy inf;
   extern MAYBE_UNUSED PosInfTy inf;
@@ -207,33 +194,4 @@ namespace embree
   };
   };
 
 
   extern MAYBE_UNUSED UndefinedTy undefined;
   extern MAYBE_UNUSED UndefinedTy undefined;
-    
-#if defined(__aarch64__)
-  extern const uint32x4_t movemask_mask;
-  extern const uint32x4_t vzero;
-  extern const uint32x4_t v0x80000000;
-  extern const uint32x4_t v0x7fffffff;
-  extern const uint32x4_t v000F;
-  extern const uint32x4_t v00F0;
-  extern const uint32x4_t v00FF;
-  extern const uint32x4_t v0F00;
-  extern const uint32x4_t v0F0F;
-  extern const uint32x4_t v0FF0;
-  extern const uint32x4_t v0FFF;
-  extern const uint32x4_t vF000;
-  extern const uint32x4_t vF00F;
-  extern const uint32x4_t vF0F0;
-  extern const uint32x4_t vF0FF;
-  extern const uint32x4_t vFF00;
-  extern const uint32x4_t vFF0F;
-  extern const uint32x4_t vFFF0;
-  extern const uint32x4_t vFFFF;
-  extern const uint8x16_t v0022;
-  extern const uint8x16_t v1133;
-  extern const uint8x16_t v0101;
-  extern const float32x4_t vOne;
-  extern const float32x4_t vmOne;
-  extern const float32x4_t vInf;
-  extern const float32x4_t vmInf;
-#endif
 }
 }

+ 1 - 1
thirdparty/embree-aarch64/common/math/interval.h → thirdparty/embree/common/math/interval.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/math/lbbox.h → thirdparty/embree/common/math/lbbox.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/math/linearspace2.h → thirdparty/embree/common/math/linearspace2.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/math/linearspace3.h → thirdparty/embree/common/math/linearspace3.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 29 - 111
thirdparty/embree-aarch64/common/math/math.h → thirdparty/embree/common/math/math.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -9,18 +9,15 @@
 #include <cmath>
 #include <cmath>
 
 
 #if defined(__ARM_NEON)
 #if defined(__ARM_NEON)
-#include "SSE2NEON.h"
-#if defined(NEON_AVX2_EMULATION)
-#include "AVX2NEON.h"
-#endif
+#include "../simd/arm/emulation.h"
 #else
 #else
 #include <emmintrin.h>
 #include <emmintrin.h>
 #include <xmmintrin.h>
 #include <xmmintrin.h>
 #include <immintrin.h>
 #include <immintrin.h>
 #endif
 #endif
 
 
-#if defined(__WIN32__) && !defined(__MINGW32__)
-#if (__MSV_VER <= 1700)
+#if defined(__WIN32__)
+#if defined(_MSC_VER) && (_MSC_VER <= 1700)
 namespace std
 namespace std
 {
 {
   __forceinline bool isinf ( const float x ) { return _finite(x) == 0; }
   __forceinline bool isinf ( const float x ) { return _finite(x) == 0; }
@@ -47,7 +44,7 @@ namespace embree
   __forceinline int   toInt  (const float& a) { return int(a); }
   __forceinline int   toInt  (const float& a) { return int(a); }
   __forceinline float toFloat(const int&   a) { return float(a); }
   __forceinline float toFloat(const int&   a) { return float(a); }
 
 
-#if defined(__WIN32__) && !defined(__MINGW32__)
+#if defined(__WIN32__)
   __forceinline bool finite ( const float x ) { return _finite(x) != 0; }
   __forceinline bool finite ( const float x ) { return _finite(x) != 0; }
 #endif
 #endif
 
 
@@ -56,16 +53,6 @@ namespace embree
 
 
   __forceinline float rcp  ( const float x )
   __forceinline float rcp  ( const float x )
   {
   {
-#if defined(__aarch64__)
-      // Move scalar to vector register and do rcp.
-      __m128 a;
-      a[0] = x;
-      float32x4_t reciprocal = vrecpeq_f32(a);
-      reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
-      reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
-      return reciprocal[0];
-#else
-
     const __m128 a = _mm_set_ss(x);
     const __m128 a = _mm_set_ss(x);
 
 
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
@@ -79,74 +66,33 @@ namespace embree
 #else
 #else
     return _mm_cvtss_f32(_mm_mul_ss(r,_mm_sub_ss(_mm_set_ss(2.0f), _mm_mul_ss(r, a))));
     return _mm_cvtss_f32(_mm_mul_ss(r,_mm_sub_ss(_mm_set_ss(2.0f), _mm_mul_ss(r, a))));
 #endif
 #endif
-
-#endif  //defined(__aarch64__)
   }
   }
 
 
   __forceinline float signmsk ( const float x ) {
   __forceinline float signmsk ( const float x ) {
-#if defined(__aarch64__)
-      // FP and Neon shares same vector register in arm64
-      __m128 a;
-      __m128i b;
-      a[0] = x;
-      b[0] = 0x80000000;
-      a = _mm_and_ps(a, vreinterpretq_f32_s32(b));
-      return a[0];
-#else
     return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
     return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
-#endif
   }
   }
   __forceinline float xorf( const float x, const float y ) {
   __forceinline float xorf( const float x, const float y ) {
-#if defined(__aarch64__)
-      // FP and Neon shares same vector register in arm64
-      __m128 a;
-      __m128 b;
-      a[0] = x;
-      b[0] = y;
-      a = _mm_xor_ps(a, b);
-      return a[0];
-#else
     return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(x),_mm_set_ss(y)));
     return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(x),_mm_set_ss(y)));
-#endif
   }
   }
   __forceinline float andf( const float x, const unsigned y ) {
   __forceinline float andf( const float x, const unsigned y ) {
-#if defined(__aarch64__) 
-      // FP and Neon shares same vector register in arm64
-      __m128 a;
-      __m128i b;
-      a[0] = x;
-      b[0] = y;
-      a = _mm_and_ps(a, vreinterpretq_f32_s32(b));
-      return a[0];
-#else
     return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(y))));
     return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(y))));
-#endif
   }
   }
   __forceinline float rsqrt( const float x )
   __forceinline float rsqrt( const float x )
   {
   {
-#if defined(__aarch64__)
-      // FP and Neon shares same vector register in arm64
-      __m128 a;
-      a[0] = x;
-      __m128 value = _mm_rsqrt_ps(a);
-      value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(a, value), value));
-      value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(a, value), value));
-      return value[0];
-#else
-
     const __m128 a = _mm_set_ss(x);
     const __m128 a = _mm_set_ss(x);
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
-    const __m128 r = _mm_rsqrt14_ss(_mm_set_ss(0.0f),a);
+    __m128 r = _mm_rsqrt14_ss(_mm_set_ss(0.0f),a);
 #else
 #else
-    const __m128 r = _mm_rsqrt_ss(a);
+    __m128 r = _mm_rsqrt_ss(a);
 #endif
 #endif
-    const __m128 c = _mm_add_ss(_mm_mul_ss(_mm_set_ss(1.5f), r),
-                                _mm_mul_ss(_mm_mul_ss(_mm_mul_ss(a, _mm_set_ss(-0.5f)), r), _mm_mul_ss(r, r)));
-    return _mm_cvtss_f32(c);
+    r = _mm_add_ss(_mm_mul_ss(_mm_set_ss(1.5f), r), _mm_mul_ss(_mm_mul_ss(_mm_mul_ss(a, _mm_set_ss(-0.5f)), r), _mm_mul_ss(r, r)));
+#if defined(__ARM_NEON)
+    r = _mm_add_ss(_mm_mul_ss(_mm_set_ss(1.5f), r), _mm_mul_ss(_mm_mul_ss(_mm_mul_ss(a, _mm_set_ss(-0.5f)), r), _mm_mul_ss(r, r)));
 #endif
 #endif
+    return _mm_cvtss_f32(r);
   }
   }
 
 
-#if defined(__WIN32__) && (__MSC_VER <= 1700) && !defined(__MINGW32__)
+#if defined(__WIN32__) && defined(_MSC_VER) && (_MSC_VER <= 1700)
   __forceinline float nextafter(float x, float y) { if ((x<y) == (x>0)) return x*(1.1f+float(ulp)); else return x*(0.9f-float(ulp)); }
   __forceinline float nextafter(float x, float y) { if ((x<y) == (x>0)) return x*(1.1f+float(ulp)); else return x*(0.9f-float(ulp)); }
   __forceinline double nextafter(double x, double y) { return _nextafter(x, y); }
   __forceinline double nextafter(double x, double y) { return _nextafter(x, y); }
   __forceinline int roundf(float f) { return (int)(f + 0.5f); }
   __forceinline int roundf(float f) { return (int)(f + 0.5f); }
@@ -200,17 +146,7 @@ namespace embree
   __forceinline double floor( const double x ) { return ::floor (x); }
   __forceinline double floor( const double x ) { return ::floor (x); }
   __forceinline double ceil ( const double x ) { return ::ceil (x); }
   __forceinline double ceil ( const double x ) { return ::ceil (x); }
 
 
-#if defined(__aarch64__) 
-    __forceinline float mini(float a, float b) {
-        // FP and Neon shares same vector register in arm64
-        __m128 x;
-        __m128 y;
-        x[0] = a;
-        y[0] = b;
-        x = _mm_min_ps(x, y);
-        return x[0];
-    }
-#elif defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline float mini(float a, float b) {
   __forceinline float mini(float a, float b) {
     const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
     const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
     const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
     const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
@@ -219,17 +155,7 @@ namespace embree
   }
   }
 #endif
 #endif
 
 
-#if defined(__aarch64__) 
-    __forceinline float maxi(float a, float b) {
-        // FP and Neon shares same vector register in arm64
-        __m128 x;
-        __m128 y;
-        x[0] = a;
-        y[0] = b;
-        x = _mm_max_ps(x, y);
-        return x[0];
-    }
-#elif defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline float maxi(float a, float b) {
   __forceinline float maxi(float a, float b) {
     const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
     const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
     const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
     const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
@@ -246,7 +172,7 @@ namespace embree
   __forceinline  int64_t min(int64_t  a, int64_t  b) { return a<b ? a:b; }
   __forceinline  int64_t min(int64_t  a, int64_t  b) { return a<b ? a:b; }
   __forceinline    float min(float    a, float    b) { return a<b ? a:b; }
   __forceinline    float min(float    a, float    b) { return a<b ? a:b; }
   __forceinline   double min(double   a, double   b) { return a<b ? a:b; }
   __forceinline   double min(double   a, double   b) { return a<b ? a:b; }
-#if defined(__X86_64__) || defined(__aarch64__)
+#if defined(__64BIT__)
   __forceinline   size_t min(size_t   a, size_t   b) { return a<b ? a:b; }
   __forceinline   size_t min(size_t   a, size_t   b) { return a<b ? a:b; }
 #endif
 #endif
 
 
@@ -263,7 +189,7 @@ namespace embree
   __forceinline  int64_t max(int64_t  a, int64_t  b) { return a<b ? b:a; }
   __forceinline  int64_t max(int64_t  a, int64_t  b) { return a<b ? b:a; }
   __forceinline    float max(float    a, float    b) { return a<b ? b:a; }
   __forceinline    float max(float    a, float    b) { return a<b ? b:a; }
   __forceinline   double max(double   a, double   b) { return a<b ? b:a; }
   __forceinline   double max(double   a, double   b) { return a<b ? b:a; }
-#if defined(__X86_64__) || defined(__aarch64__)
+#if defined(__64BIT__)
   __forceinline   size_t max(size_t   a, size_t   b) { return a<b ? b:a; }
   __forceinline   size_t max(size_t   a, size_t   b) { return a<b ? b:a; }
 #endif
 #endif
 
 
@@ -305,16 +231,6 @@ namespace embree
   __forceinline float msub  ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
   __forceinline float msub  ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
   __forceinline float nmadd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
   __forceinline float nmadd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
   __forceinline float nmsub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
   __forceinline float nmsub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
-#elif defined (__aarch64__) && defined(__clang__)
-#pragma clang fp contract(fast)
-
-
-__forceinline float madd  ( const float a, const float b, const float c) { return a*b + c; }
-__forceinline float msub  ( const float a, const float b, const float c) { return a*b - c; }
-__forceinline float nmadd ( const float a, const float b, const float c) { return c - a*b; }
-__forceinline float nmsub ( const float a, const float b, const float c) { return -(c + a*b); }
-
-#pragma clang fp contract(on)
 #else
 #else
   __forceinline float madd  ( const float a, const float b, const float c) { return a*b+c; }
   __forceinline float madd  ( const float a, const float b, const float c) { return a*b+c; }
   __forceinline float msub  ( const float a, const float b, const float c) { return a*b-c; }
   __forceinline float msub  ( const float a, const float b, const float c) { return a*b-c; }
@@ -363,15 +279,17 @@ __forceinline float nmsub ( const float a, const float b, const float c) { retur
   /*! exchange */
   /*! exchange */
   template<typename T> __forceinline void xchg ( T& a, T& b ) { const T tmp = a; a = b; b = tmp; }
   template<typename T> __forceinline void xchg ( T& a, T& b ) { const T tmp = a; a = b; b = tmp; }
 
 
-
-  template<typename T> __forceinline T prod_diff(const T& a,const T& b,const T& c,const T& d) {
-#if 1//!defined(__aarch64__)
-      return msub(a,b,c*d);
-#else
-      return nmadd(c,d,a*b);
-#endif
-  }
-
+  /*  load/store */
+  template<typename Ty> struct mem;
+ 
+  template<> struct mem<float> {
+    static __forceinline float load (bool mask, const void* ptr) { return mask ? *(float*)ptr : 0.0f; }
+    static __forceinline float loadu(bool mask, const void* ptr) { return mask ? *(float*)ptr : 0.0f; }
+  
+    static __forceinline void store (bool mask, void* ptr, const float v) { if (mask) *(float*)ptr = v; }
+    static __forceinline void storeu(bool mask, void* ptr, const float v) { if (mask) *(float*)ptr = v; }
+  };
+  
   /*! bit reverse operation */
   /*! bit reverse operation */
   template<class T>
   template<class T>
     __forceinline T bitReverse(const T& vin)
     __forceinline T bitReverse(const T& vin)
@@ -389,7 +307,7 @@ __forceinline float nmsub ( const float a, const float b, const float c) { retur
   template<class T>
   template<class T>
     __forceinline T bitInterleave(const T& xin, const T& yin, const T& zin)
     __forceinline T bitInterleave(const T& xin, const T& yin, const T& zin)
   {
   {
-	  T x = xin, y = yin, z = zin;
+	T x = xin, y = yin, z = zin;
     x = (x | (x << 16)) & 0x030000FF;
     x = (x | (x << 16)) & 0x030000FF;
     x = (x | (x <<  8)) & 0x0300F00F;
     x = (x | (x <<  8)) & 0x0300F00F;
     x = (x | (x <<  4)) & 0x030C30C3;
     x = (x | (x <<  4)) & 0x030C30C3;
@@ -408,7 +326,7 @@ __forceinline float nmsub ( const float a, const float b, const float c) { retur
     return x | (y << 1) | (z << 2);
     return x | (y << 1) | (z << 2);
   }
   }
 
 
-#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__AVX2__)
 
 
   template<>
   template<>
     __forceinline unsigned int bitInterleave(const unsigned int &xi, const unsigned int& yi, const unsigned int& zi)
     __forceinline unsigned int bitInterleave(const unsigned int &xi, const unsigned int& yi, const unsigned int& zi)

+ 1 - 1
thirdparty/embree-aarch64/common/math/obbox.h → thirdparty/embree/common/math/obbox.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/math/quaternion.h → thirdparty/embree/common/math/quaternion.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/math/range.h → thirdparty/embree/common/math/range.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 2 - 2
thirdparty/embree-aarch64/common/math/transcendental.h → thirdparty/embree/common/math/transcendental.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -418,7 +418,7 @@ __forceinline void __rangeReduceLog(const T &input,
 }
 }
 
 
 template <typename T> struct ExponentType            { };
 template <typename T> struct ExponentType            { };
-template <int N>      struct ExponentType<vfloat<N>> { typedef vint<N> Ty; };
+template <int N>      struct ExponentType<vfloat_impl<N>> { typedef vint<N> Ty; };
 template <>           struct ExponentType<float>     { typedef int     Ty; };
 template <>           struct ExponentType<float>     { typedef int     Ty; };
 
 
 template <typename T>
 template <typename T>

+ 4 - 4
thirdparty/embree-aarch64/common/math/vec2.h → thirdparty/embree/common/math/vec2.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -205,11 +205,11 @@ namespace embree
 
 
 #include "vec2fa.h"
 #include "vec2fa.h"
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
+#if defined __SSE__
 #include "../simd/sse.h"
 #include "../simd/sse.h"
 #endif
 #endif
 
 
-#if defined(__AVX__)
+#if defined __AVX__
 #include "../simd/avx.h"
 #include "../simd/avx.h"
 #endif
 #endif
 
 
@@ -221,7 +221,7 @@ namespace embree
 {
 {
   template<> __forceinline Vec2<float>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
   template<> __forceinline Vec2<float>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
+#if defined(__SSE__)
   template<> __forceinline Vec2<vfloat4>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
   template<> __forceinline Vec2<vfloat4>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
 #endif
 #endif
 
 

+ 6 - 22
thirdparty/embree-aarch64/common/math/vec2fa.h → thirdparty/embree/common/math/vec2fa.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -97,12 +97,6 @@ namespace embree
 
 
   __forceinline Vec2fa rcp  ( const Vec2fa& a )
   __forceinline Vec2fa rcp  ( const Vec2fa& a )
   {
   {
-#if defined(__aarch64__)
-        __m128 reciprocal = _mm_rcp_ps(a.m128);
-        reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
-        reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
-        return (const Vec2fa)reciprocal;
-#else
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     const Vec2fa r = _mm_rcp14_ps(a.m128);
     const Vec2fa r = _mm_rcp14_ps(a.m128);
 #else
 #else
@@ -117,7 +111,6 @@ namespace embree
 #endif
 #endif
 
 
     return res;
     return res;
-#endif  //defined(__aarch64__) 
   }
   }
 
 
   __forceinline Vec2fa sqrt ( const Vec2fa& a ) { return _mm_sqrt_ps(a.m128); }
   __forceinline Vec2fa sqrt ( const Vec2fa& a ) { return _mm_sqrt_ps(a.m128); }
@@ -125,21 +118,12 @@ namespace embree
 
 
   __forceinline Vec2fa rsqrt( const Vec2fa& a )
   __forceinline Vec2fa rsqrt( const Vec2fa& a )
   {
   {
-#if defined(__aarch64__)
-        __m128 r = _mm_rsqrt_ps(a.m128);
-        r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
-        r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
-        return r;
-#else
-        
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     __m128 r = _mm_rsqrt14_ps(a.m128);
     __m128 r = _mm_rsqrt14_ps(a.m128);
 #else
 #else
     __m128 r = _mm_rsqrt_ps(a.m128);
     __m128 r = _mm_rsqrt_ps(a.m128);
 #endif
 #endif
     return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
     return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
-        
-#endif
   }
   }
 
 
   __forceinline Vec2fa zero_fix(const Vec2fa& a) {
   __forceinline Vec2fa zero_fix(const Vec2fa& a) {
@@ -172,7 +156,7 @@ namespace embree
   __forceinline Vec2fa min( const Vec2fa& a, const Vec2fa& b ) { return _mm_min_ps(a.m128,b.m128); }
   __forceinline Vec2fa min( const Vec2fa& a, const Vec2fa& b ) { return _mm_min_ps(a.m128,b.m128); }
   __forceinline Vec2fa max( const Vec2fa& a, const Vec2fa& b ) { return _mm_max_ps(a.m128,b.m128); }
   __forceinline Vec2fa max( const Vec2fa& a, const Vec2fa& b ) { return _mm_max_ps(a.m128,b.m128); }
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     __forceinline Vec2fa mini(const Vec2fa& a, const Vec2fa& b) {
     __forceinline Vec2fa mini(const Vec2fa& a, const Vec2fa& b) {
       const vint4 ai = _mm_castps_si128(a);
       const vint4 ai = _mm_castps_si128(a);
       const vint4 bi = _mm_castps_si128(b);
       const vint4 bi = _mm_castps_si128(b);
@@ -181,7 +165,7 @@ namespace embree
     }
     }
 #endif
 #endif
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     __forceinline Vec2fa maxi(const Vec2fa& a, const Vec2fa& b) {
     __forceinline Vec2fa maxi(const Vec2fa& a, const Vec2fa& b) {
       const vint4 ai = _mm_castps_si128(a);
       const vint4 ai = _mm_castps_si128(a);
       const vint4 bi = _mm_castps_si128(b);
       const vint4 bi = _mm_castps_si128(b);
@@ -292,9 +276,9 @@ namespace embree
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
 #if defined(__aarch64__)
 #if defined(__aarch64__)
-__forceinline Vec2fa floor(const Vec2fa& a) { return vrndmq_f32(a); }
-__forceinline Vec2fa ceil (const Vec2fa& a) { return vrndpq_f32(a); }
-//__forceinline Vec2fa trunc(const Vec2fa& a) { return vrndq_f32(a); }
+  //__forceinline Vec2fa trunc(const Vec2fa& a) { return vrndq_f32(a); }
+  __forceinline Vec2fa floor(const Vec2fa& a) { return vrndmq_f32(a); }
+  __forceinline Vec2fa ceil (const Vec2fa& a) { return vrndpq_f32(a); }
 #elif defined (__SSE4_1__)
 #elif defined (__SSE4_1__)
   //__forceinline Vec2fa trunc( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
   //__forceinline Vec2fa trunc( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
   __forceinline Vec2fa floor( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline Vec2fa floor( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF    ); }

+ 7 - 19
thirdparty/embree-aarch64/common/math/vec3.h → thirdparty/embree/common/math/vec3.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -206,7 +206,8 @@ namespace embree
   template<typename T> __forceinline T       rcp_length( const Vec3<T>& a )                  { return rsqrt(sqr(a)); }
   template<typename T> __forceinline T       rcp_length( const Vec3<T>& a )                  { return rsqrt(sqr(a)); }
   template<typename T> __forceinline Vec3<T> normalize( const Vec3<T>& a )                   { return a*rsqrt(sqr(a)); }
   template<typename T> __forceinline Vec3<T> normalize( const Vec3<T>& a )                   { return a*rsqrt(sqr(a)); }
   template<typename T> __forceinline T       distance ( const Vec3<T>& a, const Vec3<T>& b ) { return length(a-b); }
   template<typename T> __forceinline T       distance ( const Vec3<T>& a, const Vec3<T>& b ) { return length(a-b); }
-  template<typename T> __forceinline Vec3<T> cross    ( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(prod_diff(a.y,b.z,a.z,b.y), prod_diff(a.z,b.x,a.x,b.z), prod_diff(a.x,b.y,a.y,b.x)); }
+  template<typename T> __forceinline Vec3<T> cross    ( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(msub(a.y,b.z,a.z*b.y), msub(a.z,b.x,a.x*b.z), msub(a.x,b.y,a.y*b.x)); }
+
   template<typename T> __forceinline Vec3<T> stable_triangle_normal( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c )
   template<typename T> __forceinline Vec3<T> stable_triangle_normal( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c )
   {
   {
     const T ab_x = a.z*b.y, ab_y = a.x*b.z, ab_z = a.y*b.x;
     const T ab_x = a.z*b.y, ab_y = a.x*b.z, ab_z = a.y*b.x;
@@ -265,11 +266,11 @@ namespace embree
 /// SSE / AVX / MIC specializations
 /// SSE / AVX / MIC specializations
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
+#if defined __SSE__
 #include "../simd/sse.h"
 #include "../simd/sse.h"
 #endif
 #endif
 
 
-#if defined(__AVX__)
+#if defined __AVX__
 #include "../simd/avx.h"
 #include "../simd/avx.h"
 #endif
 #endif
 
 
@@ -290,18 +291,14 @@ namespace embree
   template<> __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
   template<> __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
     x = a.x; y = a.y; z = a.z;
     x = a.x; y = a.y; z = a.z;
   }
   }
-#elif defined(__SSE__) || defined(__ARM_NEON)
+#elif defined(__SSE__)
   template<>
   template<>
   __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
   __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
     const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v);
     const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v);
   }
   }
 #endif
 #endif
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
-  __forceinline Vec3<vfloat4> broadcast4f(const Vec3<vfloat4>& a, const size_t k) {
-    return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
-  }
-
+#if defined(__SSE__)
   template<>
   template<>
   __forceinline Vec3<vfloat4> broadcast<vfloat4,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
   __forceinline Vec3<vfloat4> broadcast<vfloat4,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
     return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
     return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
@@ -318,15 +315,6 @@ namespace embree
   __forceinline Vec3<vfloat8>::Vec3(const Vec3fa& a) {
   __forceinline Vec3<vfloat8>::Vec3(const Vec3fa& a) {
     x = a.x; y = a.y; z = a.z;
     x = a.x; y = a.y; z = a.z;
   }
   }
-  __forceinline Vec3<vfloat4> broadcast4f(const Vec3<vfloat8>& a, const size_t k) {
-    return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
-  }
-  __forceinline Vec3<vfloat8> broadcast8f(const Vec3<vfloat4>& a, const size_t k) {
-    return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
-  }
-  __forceinline Vec3<vfloat8> broadcast8f(const Vec3<vfloat8>& a, const size_t k) {
-    return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
-  }
 
 
   template<>
   template<>
   __forceinline Vec3<vfloat8> broadcast<vfloat8,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
   __forceinline Vec3<vfloat8> broadcast<vfloat8,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {

+ 1 - 1
thirdparty/embree-aarch64/common/math/vec3ba.h → thirdparty/embree/common/math/vec3ba.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 23 - 106
thirdparty/embree-aarch64/common/math/vec3fa.h → thirdparty/embree/common/math/vec3fa.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -55,13 +55,7 @@ namespace embree
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
 
 
     static __forceinline Vec3fa load( const void* const a ) {
     static __forceinline Vec3fa load( const void* const a ) {
-#if defined(__aarch64__)
-        __m128 t = _mm_load_ps((float*)a);
-        t[3] = 0.0f;
-        return Vec3fa(t);
-#else
       return Vec3fa(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))));
       return Vec3fa(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))));
-#endif
     }
     }
 
 
     static __forceinline Vec3fa loadu( const void* const a ) {
     static __forceinline Vec3fa loadu( const void* const a ) {
@@ -95,42 +89,19 @@ namespace embree
 
 
   __forceinline Vec3fa operator +( const Vec3fa& a ) { return a; }
   __forceinline Vec3fa operator +( const Vec3fa& a ) { return a; }
   __forceinline Vec3fa operator -( const Vec3fa& a ) {
   __forceinline Vec3fa operator -( const Vec3fa& a ) {
-#if defined(__aarch64__)
-    return vnegq_f32(a.m128);
-#else
     const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
     const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
-
     return _mm_xor_ps(a.m128, mask);
     return _mm_xor_ps(a.m128, mask);
-#endif
   }
   }
   __forceinline Vec3fa abs  ( const Vec3fa& a ) {
   __forceinline Vec3fa abs  ( const Vec3fa& a ) {
-#if defined(__aarch64__)
-    return _mm_abs_ps(a.m128);
-#else
     const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
     const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
     return _mm_and_ps(a.m128, mask);
     return _mm_and_ps(a.m128, mask);
-#endif
   }
   }
   __forceinline Vec3fa sign ( const Vec3fa& a ) {
   __forceinline Vec3fa sign ( const Vec3fa& a ) {
-#if defined(__aarch64__)
-    Vec3fa r = blendv_ps(vOne, vmOne, _mm_cmplt_ps (a.m128,vdupq_n_f32(0.0f)));
-    return r;
-#else
     return blendv_ps(Vec3fa(one).m128, (-Vec3fa(one)).m128, _mm_cmplt_ps (a.m128,Vec3fa(zero).m128));
     return blendv_ps(Vec3fa(one).m128, (-Vec3fa(one)).m128, _mm_cmplt_ps (a.m128,Vec3fa(zero).m128));
-#endif
   }
   }
 
 
   __forceinline Vec3fa rcp  ( const Vec3fa& a )
   __forceinline Vec3fa rcp  ( const Vec3fa& a )
   {
   {
-#if defined(__aarch64__) && defined(BUILD_IOS)
-  return vdivq_f32(vdupq_n_f32(1.0f),a.m128);
-#elif defined(__aarch64__)
-  __m128 reciprocal = _mm_rcp_ps(a.m128);
-  reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
-  reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
-  return (const Vec3fa)reciprocal;
-#else
-        
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     const Vec3fa r = _mm_rcp14_ps(a.m128);
     const Vec3fa r = _mm_rcp14_ps(a.m128);
 #else
 #else
@@ -145,7 +116,6 @@ namespace embree
 #endif
 #endif
 
 
     return res;
     return res;
-#endif  //defined(__aarch64__)
   }
   }
 
 
   __forceinline Vec3fa sqrt ( const Vec3fa& a ) { return _mm_sqrt_ps(a.m128); }
   __forceinline Vec3fa sqrt ( const Vec3fa& a ) { return _mm_sqrt_ps(a.m128); }
@@ -153,20 +123,12 @@ namespace embree
 
 
   __forceinline Vec3fa rsqrt( const Vec3fa& a )
   __forceinline Vec3fa rsqrt( const Vec3fa& a )
   {
   {
-#if defined(__aarch64__)
-        __m128 r = _mm_rsqrt_ps(a.m128);
-        r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
-        r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
-        return r;
-#else
-        
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     __m128 r = _mm_rsqrt14_ps(a.m128);
     __m128 r = _mm_rsqrt14_ps(a.m128);
 #else
 #else
     __m128 r = _mm_rsqrt_ps(a.m128);
     __m128 r = _mm_rsqrt_ps(a.m128);
 #endif
 #endif
     return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a.m128, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
     return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a.m128, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
-#endif
   }
   }
 
 
   __forceinline Vec3fa zero_fix(const Vec3fa& a) {
   __forceinline Vec3fa zero_fix(const Vec3fa& a) {
@@ -199,7 +161,7 @@ namespace embree
   __forceinline Vec3fa min( const Vec3fa& a, const Vec3fa& b ) { return _mm_min_ps(a.m128,b.m128); }
   __forceinline Vec3fa min( const Vec3fa& a, const Vec3fa& b ) { return _mm_min_ps(a.m128,b.m128); }
   __forceinline Vec3fa max( const Vec3fa& a, const Vec3fa& b ) { return _mm_max_ps(a.m128,b.m128); }
   __forceinline Vec3fa max( const Vec3fa& a, const Vec3fa& b ) { return _mm_max_ps(a.m128,b.m128); }
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     __forceinline Vec3fa mini(const Vec3fa& a, const Vec3fa& b) {
     __forceinline Vec3fa mini(const Vec3fa& a, const Vec3fa& b) {
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
@@ -208,7 +170,7 @@ namespace embree
     }
     }
 #endif
 #endif
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     __forceinline Vec3fa maxi(const Vec3fa& a, const Vec3fa& b) {
     __forceinline Vec3fa maxi(const Vec3fa& a, const Vec3fa& b) {
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
@@ -230,30 +192,11 @@ namespace embree
   __forceinline Vec3fa msub  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fmsub_ps(a.m128,b.m128,c.m128); }
   __forceinline Vec3fa msub  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fmsub_ps(a.m128,b.m128,c.m128); }
   __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmadd_ps(a.m128,b.m128,c.m128); }
   __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmadd_ps(a.m128,b.m128,c.m128); }
   __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmsub_ps(a.m128,b.m128,c.m128); }
   __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmsub_ps(a.m128,b.m128,c.m128); }
-#else
-                                                                                
-#if defined(__aarch64__)
-  __forceinline Vec3fa madd  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
-        return _mm_madd_ps(a.m128, b.m128, c.m128);  //a*b+c;
-    }
-  __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
-        return _mm_msub_ps(a.m128, b.m128, c.m128);  //-a*b+c;
-    }
-  __forceinline Vec3fa nmsub( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
-        Vec3fa t = _mm_madd_ps(a.m128, b.m128, c.m128);
-        return -t;
-    }
-  __forceinline Vec3fa msub( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
-        return _mm_madd_ps(a.m128,b.m128,vnegq_f32(c.m128)); //a*b-c
-    }
-
 #else
 #else
   __forceinline Vec3fa madd  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b+c; }
   __forceinline Vec3fa madd  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b+c; }
+  __forceinline Vec3fa msub  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b-c; }
   __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b+c;}
   __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b+c;}
   __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b-c; }
   __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b-c; }
-  __forceinline Vec3fa msub  ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b-c; }
-#endif
-
 #endif
 #endif
 
 
   __forceinline Vec3fa madd  ( const float a, const Vec3fa& b, const Vec3fa& c) { return madd(Vec3fa(a),b,c); }
   __forceinline Vec3fa madd  ( const float a, const Vec3fa& b, const Vec3fa& c) { return madd(Vec3fa(a),b,c); }
@@ -275,37 +218,18 @@ namespace embree
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
-#if defined(__aarch64__) && defined(BUILD_IOS)
-  __forceinline float reduce_add(const Vec3fa& v) {
-    float32x4_t t = v.m128;
-    t[3] = 0.0f;
-    return vaddvq_f32(t);
-  }
-                                                                                
-  __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; }
-  __forceinline float reduce_min(const Vec3fa& v) {
-    float32x4_t t = v.m128;
-      t[3] = t[2];
-    return vminvq_f32(t);
-  }
-  __forceinline float reduce_max(const Vec3fa& v) {
-    float32x4_t t = v.m128;
-      t[3] = t[2];
-    return vmaxvq_f32(t);
-  }
-#else
-  __forceinline float reduce_add(const Vec3fa& v) {
+
+  __forceinline float reduce_add(const Vec3fa& v) { 
     const vfloat4 a(v.m128);
     const vfloat4 a(v.m128);
     const vfloat4 b = shuffle<1>(a);
     const vfloat4 b = shuffle<1>(a);
     const vfloat4 c = shuffle<2>(a);
     const vfloat4 c = shuffle<2>(a);
-    return _mm_cvtss_f32(a+b+c);
+    return _mm_cvtss_f32(a+b+c); 
   }
   }
 
 
   __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; }
   __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; }
   __forceinline float reduce_min(const Vec3fa& v) { return min(v.x,v.y,v.z); }
   __forceinline float reduce_min(const Vec3fa& v) { return min(v.x,v.y,v.z); }
   __forceinline float reduce_max(const Vec3fa& v) { return max(v.x,v.y,v.z); }
   __forceinline float reduce_max(const Vec3fa& v) { return max(v.x,v.y,v.z); }
-#endif
-                                                                                
+
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Comparison Operators
   /// Comparison Operators
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -317,13 +241,8 @@ namespace embree
   __forceinline Vec3ba neq_mask(const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpneq_ps(a.m128, b.m128); }
   __forceinline Vec3ba neq_mask(const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpneq_ps(a.m128, b.m128); }
   __forceinline Vec3ba lt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmplt_ps (a.m128, b.m128); }
   __forceinline Vec3ba lt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmplt_ps (a.m128, b.m128); }
   __forceinline Vec3ba le_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmple_ps (a.m128, b.m128); }
   __forceinline Vec3ba le_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmple_ps (a.m128, b.m128); }
- #if defined(__aarch64__)
-  __forceinline Vec3ba gt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpgt_ps (a.m128, b.m128); }
-  __forceinline Vec3ba ge_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpge_ps (a.m128, b.m128); }
-#else
-  __forceinline Vec3ba gt_mask(const Vec3fa& a, const Vec3fa& b) { return _mm_cmpnle_ps(a.m128, b.m128); }
-  __forceinline Vec3ba ge_mask(const Vec3fa& a, const Vec3fa& b) { return _mm_cmpnlt_ps(a.m128, b.m128); }
-#endif
+  __forceinline Vec3ba gt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpnle_ps(a.m128, b.m128); }
+  __forceinline Vec3ba ge_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpnlt_ps(a.m128, b.m128); }
 
 
   __forceinline bool isvalid ( const Vec3fa& v ) {
   __forceinline bool isvalid ( const Vec3fa& v ) {
     return all(gt_mask(v,Vec3fa(-FLT_LARGE)) & lt_mask(v,Vec3fa(+FLT_LARGE)));
     return all(gt_mask(v,Vec3fa(-FLT_LARGE)) & lt_mask(v,Vec3fa(+FLT_LARGE)));
@@ -361,7 +280,7 @@ namespace embree
     vfloat4 b0 = shuffle<1,2,0,3>(vfloat4(b.m128));
     vfloat4 b0 = shuffle<1,2,0,3>(vfloat4(b.m128));
     vfloat4 a1 = shuffle<1,2,0,3>(vfloat4(a.m128));
     vfloat4 a1 = shuffle<1,2,0,3>(vfloat4(a.m128));
     vfloat4 b1 = vfloat4(b.m128);
     vfloat4 b1 = vfloat4(b.m128);
-    return Vec3fa(shuffle<1,2,0,3>(prod_diff(a0,b0,a1,b1)));
+    return Vec3fa(shuffle<1,2,0,3>(msub(a0,b0,a1*b1)));
   }
   }
 
 
   __forceinline float  sqr_length ( const Vec3fa& a )                { return dot(a,a); }
   __forceinline float  sqr_length ( const Vec3fa& a )                { return dot(a,a); }
@@ -416,11 +335,7 @@ namespace embree
   /// Rounding Functions
   /// Rounding Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined(__aarch64__)
-  __forceinline Vec3fa floor(const Vec3fa& a) { return vrndmq_f32(a.m128); }
-  __forceinline Vec3fa ceil (const Vec3fa& a) { return vrndpq_f32(a.m128); }
-  __forceinline Vec3fa trunc(const Vec3fa& a) { return vrndq_f32(a.m128); }
-#elif defined (__SSE4_1__)
+#if defined (__SSE4_1__)
   __forceinline Vec3fa trunc( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
   __forceinline Vec3fa trunc( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
   __forceinline Vec3fa floor( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline Vec3fa floor( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline Vec3fa ceil ( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF    ); }
   __forceinline Vec3fa ceil ( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF    ); }
@@ -478,10 +393,8 @@ namespace embree
 
 
     __forceinline Vec3fx( const Vec3fa& other, const int      a1) { m128 = other.m128; a = a1; }
     __forceinline Vec3fx( const Vec3fa& other, const int      a1) { m128 = other.m128; a = a1; }
     __forceinline Vec3fx( const Vec3fa& other, const unsigned a1) { m128 = other.m128; u = a1; }
     __forceinline Vec3fx( const Vec3fa& other, const unsigned a1) { m128 = other.m128; u = a1; }
-    __forceinline Vec3fx( const Vec3fa& other, const float    w1) {
-#if defined (__aarch64__)
-      m128 = other.m128; m128[3] = w1;
-#elif defined (__SSE4_1__)
+    __forceinline Vec3fx( const Vec3fa& other, const float    w1) {      
+#if defined (__SSE4_1__)
       m128 = _mm_insert_ps(other.m128, _mm_set_ss(w1),3 << 4);
       m128 = _mm_insert_ps(other.m128, _mm_set_ss(w1),3 << 4);
 #else
 #else
       const vint4 mask(-1,-1,-1,0);
       const vint4 mask(-1,-1,-1,0);
@@ -613,7 +526,7 @@ namespace embree
   __forceinline Vec3fx min( const Vec3fx& a, const Vec3fx& b ) { return _mm_min_ps(a.m128,b.m128); }
   __forceinline Vec3fx min( const Vec3fx& a, const Vec3fx& b ) { return _mm_min_ps(a.m128,b.m128); }
   __forceinline Vec3fx max( const Vec3fx& a, const Vec3fx& b ) { return _mm_max_ps(a.m128,b.m128); }
   __forceinline Vec3fx max( const Vec3fx& a, const Vec3fx& b ) { return _mm_max_ps(a.m128,b.m128); }
 
 
-#if defined(__SSE4_1__) || defined(__aarch64__)
+#if defined(__SSE4_1__)
     __forceinline Vec3fx mini(const Vec3fx& a, const Vec3fx& b) {
     __forceinline Vec3fx mini(const Vec3fx& a, const Vec3fx& b) {
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
@@ -622,7 +535,7 @@ namespace embree
     }
     }
 #endif
 #endif
 
 
-#if defined(__SSE4_1__) || defined(__aarch64__)
+#if defined(__SSE4_1__)
     __forceinline Vec3fx maxi(const Vec3fx& a, const Vec3fx& b) {
     __forceinline Vec3fx maxi(const Vec3fx& a, const Vec3fx& b) {
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 ai = _mm_castps_si128(a.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
       const vint4 bi = _mm_castps_si128(b.m128);
@@ -671,11 +584,11 @@ namespace embree
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-  __forceinline float reduce_add(const Vec3fx& v) {
+  __forceinline float reduce_add(const Vec3fx& v) { 
     const vfloat4 a(v.m128);
     const vfloat4 a(v.m128);
     const vfloat4 b = shuffle<1>(a);
     const vfloat4 b = shuffle<1>(a);
     const vfloat4 c = shuffle<2>(a);
     const vfloat4 c = shuffle<2>(a);
-    return _mm_cvtss_f32(a+b+c);
+    return _mm_cvtss_f32(a+b+c); 
   }
   }
 
 
   __forceinline float reduce_mul(const Vec3fx& v) { return v.x*v.y*v.z; }
   __forceinline float reduce_mul(const Vec3fx& v) { return v.x*v.y*v.z; }
@@ -787,7 +700,11 @@ namespace embree
   /// Rounding Functions
   /// Rounding Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined (__SSE4_1__) && !defined(__aarch64__)
+#if defined(__aarch64__)
+  __forceinline Vec3fx trunc(const Vec3fx& a) { return vrndq_f32(a.m128); }
+  __forceinline Vec3fx floor(const Vec3fx& a) { return vrndmq_f32(a.m128); }
+  __forceinline Vec3fx ceil (const Vec3fx& a) { return vrndpq_f32(a.m128); }
+#elif defined (__SSE4_1__)
   __forceinline Vec3fx trunc( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
   __forceinline Vec3fx trunc( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
   __forceinline Vec3fx floor( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline Vec3fx floor( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline Vec3fx ceil ( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF    ); }
   __forceinline Vec3fx ceil ( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF    ); }

+ 8 - 32
thirdparty/embree-aarch64/common/math/vec3ia.h → thirdparty/embree/common/math/vec3ia.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -65,9 +65,7 @@ namespace embree
 
 
   __forceinline Vec3ia operator +( const Vec3ia& a ) { return a; }
   __forceinline Vec3ia operator +( const Vec3ia& a ) { return a; }
   __forceinline Vec3ia operator -( const Vec3ia& a ) { return _mm_sub_epi32(_mm_setzero_si128(), a.m128); }
   __forceinline Vec3ia operator -( const Vec3ia& a ) { return _mm_sub_epi32(_mm_setzero_si128(), a.m128); }
-#if (defined(__aarch64__)) 
-  __forceinline Vec3ia abs       ( const Vec3ia& a ) { return vabsq_s32(a.m128); }
-#elif defined(__SSSE3__)
+#if defined(__SSSE3__)
   __forceinline Vec3ia abs       ( const Vec3ia& a ) { return _mm_abs_epi32(a.m128); }
   __forceinline Vec3ia abs       ( const Vec3ia& a ) { return _mm_abs_epi32(a.m128); }
 #endif
 #endif
 
 
@@ -83,7 +81,7 @@ namespace embree
   __forceinline Vec3ia operator -( const Vec3ia& a, const int     b ) { return a-Vec3ia(b); }
   __forceinline Vec3ia operator -( const Vec3ia& a, const int     b ) { return a-Vec3ia(b); }
   __forceinline Vec3ia operator -( const int     a, const Vec3ia& b ) { return Vec3ia(a)-b; }
   __forceinline Vec3ia operator -( const int     a, const Vec3ia& b ) { return Vec3ia(a)-b; }
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline Vec3ia operator *( const Vec3ia& a, const Vec3ia& b ) { return _mm_mullo_epi32(a.m128, b.m128); }
   __forceinline Vec3ia operator *( const Vec3ia& a, const Vec3ia& b ) { return _mm_mullo_epi32(a.m128, b.m128); }
   __forceinline Vec3ia operator *( const Vec3ia& a, const int     b ) { return a * Vec3ia(b); }
   __forceinline Vec3ia operator *( const Vec3ia& a, const int     b ) { return a * Vec3ia(b); }
   __forceinline Vec3ia operator *( const int     a, const Vec3ia& b ) { return Vec3ia(a) * b; }
   __forceinline Vec3ia operator *( const int     a, const Vec3ia& b ) { return Vec3ia(a) * b; }
@@ -101,14 +99,12 @@ namespace embree
   __forceinline Vec3ia operator ^( const Vec3ia& a, const int     b ) { return a ^ Vec3ia(b); }
   __forceinline Vec3ia operator ^( const Vec3ia& a, const int     b ) { return a ^ Vec3ia(b); }
   __forceinline Vec3ia operator ^( const int     a, const Vec3ia& b ) { return Vec3ia(a) ^ b; }
   __forceinline Vec3ia operator ^( const int     a, const Vec3ia& b ) { return Vec3ia(a) ^ b; }
 
 
-#if !defined(__ARM_NEON)
   __forceinline Vec3ia operator <<( const Vec3ia& a, const int n ) { return _mm_slli_epi32(a.m128, n); }
   __forceinline Vec3ia operator <<( const Vec3ia& a, const int n ) { return _mm_slli_epi32(a.m128, n); }
   __forceinline Vec3ia operator >>( const Vec3ia& a, const int n ) { return _mm_srai_epi32(a.m128, n); }
   __forceinline Vec3ia operator >>( const Vec3ia& a, const int n ) { return _mm_srai_epi32(a.m128, n); }
 
 
   __forceinline Vec3ia sll ( const Vec3ia& a, const int b ) { return _mm_slli_epi32(a.m128, b); }
   __forceinline Vec3ia sll ( const Vec3ia& a, const int b ) { return _mm_slli_epi32(a.m128, b); }
   __forceinline Vec3ia sra ( const Vec3ia& a, const int b ) { return _mm_srai_epi32(a.m128, b); }
   __forceinline Vec3ia sra ( const Vec3ia& a, const int b ) { return _mm_srai_epi32(a.m128, b); }
   __forceinline Vec3ia srl ( const Vec3ia& a, const int b ) { return _mm_srli_epi32(a.m128, b); }
   __forceinline Vec3ia srl ( const Vec3ia& a, const int b ) { return _mm_srli_epi32(a.m128, b); }
-#endif
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Assignment Operators
   /// Assignment Operators
@@ -120,7 +116,7 @@ namespace embree
   __forceinline Vec3ia& operator -=( Vec3ia& a, const Vec3ia& b ) { return a = a - b; }
   __forceinline Vec3ia& operator -=( Vec3ia& a, const Vec3ia& b ) { return a = a - b; }
   __forceinline Vec3ia& operator -=( Vec3ia& a, const int&   b ) { return a = a - b; }
   __forceinline Vec3ia& operator -=( Vec3ia& a, const int&   b ) { return a = a - b; }
   
   
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline Vec3ia& operator *=( Vec3ia& a, const Vec3ia& b ) { return a = a * b; }
   __forceinline Vec3ia& operator *=( Vec3ia& a, const Vec3ia& b ) { return a = a * b; }
   __forceinline Vec3ia& operator *=( Vec3ia& a, const int&    b ) { return a = a * b; }
   __forceinline Vec3ia& operator *=( Vec3ia& a, const int&    b ) { return a = a * b; }
 #endif
 #endif
@@ -131,38 +127,18 @@ namespace embree
   __forceinline Vec3ia& operator |=( Vec3ia& a, const Vec3ia& b ) { return a = a | b; }
   __forceinline Vec3ia& operator |=( Vec3ia& a, const Vec3ia& b ) { return a = a | b; }
   __forceinline Vec3ia& operator |=( Vec3ia& a, const int&    b ) { return a = a | b; }
   __forceinline Vec3ia& operator |=( Vec3ia& a, const int&    b ) { return a = a | b; }
   
   
-#if !defined(__ARM_NEON)
   __forceinline Vec3ia& operator <<=( Vec3ia& a, const int& b ) { return a = a << b; }
   __forceinline Vec3ia& operator <<=( Vec3ia& a, const int& b ) { return a = a << b; }
   __forceinline Vec3ia& operator >>=( Vec3ia& a, const int& b ) { return a = a >> b; }
   __forceinline Vec3ia& operator >>=( Vec3ia& a, const int& b ) { return a = a >> b; }
-#endif
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
-#if defined(__aarch64__)
-  __forceinline int reduce_add(const Vec3ia& v) {
-    int32x4_t t = v.m128;
-    t[3] = 0;
-    return vaddvq_s32(t);
-        
-  }
-  __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; }
-  __forceinline int reduce_min(const Vec3ia& v) {
-    int32x4_t t = (__m128i)blendv_ps((__m128)v0x7fffffff, (__m128)v.m128, (__m128)vFFF0);
-    return vminvq_s32(t);
-        
-  }
-  __forceinline int reduce_max(const Vec3ia& v) {
-    int32x4_t t = (__m128i)blendv_ps((__m128)v0x80000000, (__m128)v.m128, (__m128)vFFF0);
-    return vmaxvq_s32(t);
-        
-  }
-#else
+
   __forceinline int reduce_add(const Vec3ia& v) { return v.x+v.y+v.z; }
   __forceinline int reduce_add(const Vec3ia& v) { return v.x+v.y+v.z; }
   __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; }
   __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; }
   __forceinline int reduce_min(const Vec3ia& v) { return min(v.x,v.y,v.z); }
   __forceinline int reduce_min(const Vec3ia& v) { return min(v.x,v.y,v.z); }
   __forceinline int reduce_max(const Vec3ia& v) { return max(v.x,v.y,v.z); }
   __forceinline int reduce_max(const Vec3ia& v) { return max(v.x,v.y,v.z); }
-#endif
+
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Comparison Operators
   /// Comparison Operators
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -185,14 +161,14 @@ namespace embree
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
   __forceinline Vec3ia select( const Vec3ba& m, const Vec3ia& t, const Vec3ia& f ) {
   __forceinline Vec3ia select( const Vec3ba& m, const Vec3ia& t, const Vec3ia& f ) {
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
     return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
 #else
 #else
     return _mm_or_si128(_mm_and_si128(_mm_castps_si128(m), t), _mm_andnot_si128(_mm_castps_si128(m), f)); 
     return _mm_or_si128(_mm_and_si128(_mm_castps_si128(m), t), _mm_andnot_si128(_mm_castps_si128(m), f)); 
 #endif
 #endif
   }
   }
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return _mm_min_epi32(a.m128,b.m128); }
   __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return _mm_min_epi32(a.m128,b.m128); }
   __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return _mm_max_epi32(a.m128,b.m128); }
   __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return _mm_max_epi32(a.m128,b.m128); }
 #else
 #else

+ 4 - 19
thirdparty/embree-aarch64/common/math/vec4.h → thirdparty/embree/common/math/vec4.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -192,7 +192,7 @@ namespace embree
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
   typedef Vec4<bool         > Vec4b;
   typedef Vec4<bool         > Vec4b;
-  typedef Vec4<uint8_t      > Vec4uc;
+  typedef Vec4<unsigned char> Vec4uc;
   typedef Vec4<int          > Vec4i;
   typedef Vec4<int          > Vec4i;
   typedef Vec4<float        > Vec4f;
   typedef Vec4<float        > Vec4f;
 }
 }
@@ -205,7 +205,7 @@ namespace embree
 /// SSE / AVX / MIC specializations
 /// SSE / AVX / MIC specializations
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
+#if defined __SSE__
 #include "../simd/sse.h"
 #include "../simd/sse.h"
 #endif
 #endif
 
 
@@ -225,31 +225,16 @@ namespace embree
   template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
   template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
     x = a.x; y = a.y; z = a.z; w = a.w;
     x = a.x; y = a.y; z = a.z; w = a.w;
   }
   }
-#elif defined(__SSE__) || defined(__ARM_NEON)
+#elif defined(__SSE__)
   template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
   template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
     const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v); w = shuffle<3,3,3,3>(v);
     const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v); w = shuffle<3,3,3,3>(v);
   }
   }
 #endif
 #endif
 
 
-#if defined(__SSE__) || defined(__ARM_NEON)
-  __forceinline Vec4<vfloat4> broadcast4f( const Vec4<vfloat4>& a, const size_t k ) {
-    return Vec4<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]), vfloat4::broadcast(&a.w[k]));
-  }
-#endif
-
 #if defined(__AVX__)
 #if defined(__AVX__)
   template<> __forceinline Vec4<vfloat8>::Vec4( const Vec3fx& a ) {
   template<> __forceinline Vec4<vfloat8>::Vec4( const Vec3fx& a ) {
     x = a.x; y = a.y; z = a.z; w = a.w;
     x = a.x; y = a.y; z = a.z; w = a.w;
   }
   }
-  __forceinline Vec4<vfloat4> broadcast4f( const Vec4<vfloat8>& a, const size_t k ) {
-    return Vec4<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]), vfloat4::broadcast(&a.w[k]));
-  }
-  __forceinline Vec4<vfloat8> broadcast8f( const Vec4<vfloat4>& a, const size_t k ) {
-    return Vec4<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]), vfloat8::broadcast(&a.w[k]));
-  }
-  __forceinline Vec4<vfloat8> broadcast8f( const Vec4<vfloat8>& a, const size_t k ) {
-    return Vec4<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]), vfloat8::broadcast(&a.w[k]));
-  }
 #endif
 #endif
 
 
 #if defined(__AVX512F__)
 #if defined(__AVX512F__)

+ 50 - 0
thirdparty/embree/common/simd/arm/emulation.h

@@ -0,0 +1,50 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+/* Make precision match SSE, at the cost of some performance */
+#if !defined(__aarch64__)
+#  define SSE2NEON_PRECISE_DIV 1
+#  define SSE2NEON_PRECISE_SQRT 1
+#endif
+
+#include "sse2neon.h"
+
+__forceinline __m128 _mm_fmsub_ps(__m128 a, __m128 b, __m128 c) {
+   __m128 neg_c = vreinterpretq_m128_f32(vnegq_f32(vreinterpretq_f32_m128(c)));
+  return _mm_fmadd_ps(a, b, neg_c);
+}
+
+__forceinline __m128 _mm_fnmadd_ps(__m128 a, __m128 b, __m128 c) {
+#if defined(__aarch64__)
+    return vreinterpretq_m128_f32(vfmsq_f32(vreinterpretq_f32_m128(c),
+                                            vreinterpretq_f32_m128(b),
+                                            vreinterpretq_f32_m128(a)));
+#else
+    return _mm_sub_ps(c, _mm_mul_ps(a, b));
+#endif
+}
+
+__forceinline __m128 _mm_fnmsub_ps(__m128 a, __m128 b, __m128 c) {
+  return vreinterpretq_m128_f32(vnegq_f32(vreinterpretq_f32_m128(_mm_fmadd_ps(a,b,c))));
+}
+
+
+/* Dummy defines for floating point control */
+#define _MM_MASK_MASK 0x1f80
+#define _MM_MASK_DIV_ZERO 0x200
+#define _MM_FLUSH_ZERO_ON 0x8000
+#define _MM_MASK_DENORM 0x100
+#define _MM_SET_EXCEPTION_MASK(x)
+#define _MM_SET_FLUSH_ZERO_MODE(x)
+
+__forceinline int _mm_getcsr()
+{
+  return 0;
+}
+
+__forceinline void _mm_mfence()
+{
+  __sync_synchronize();
+}

+ 6996 - 0
thirdparty/embree/common/simd/arm/sse2neon.h

@@ -0,0 +1,6996 @@
+#ifndef SSE2NEON_H
+#define SSE2NEON_H
+
+// This header file provides a simple API translation layer
+// between SSE intrinsics to their corresponding Arm/Aarch64 NEON versions
+//
+// This header file does not yet translate all of the SSE intrinsics.
+//
+// Contributors to this work are:
+//   John W. Ratcliff <[email protected]>
+//   Brandon Rowlett <[email protected]>
+//   Ken Fast <[email protected]>
+//   Eric van Beurden <[email protected]>
+//   Alexander Potylitsin <[email protected]>
+//   Hasindu Gamaarachchi <[email protected]>
+//   Jim Huang <[email protected]>
+//   Mark Cheng <[email protected]>
+//   Malcolm James MacLeod <[email protected]>
+//   Devin Hussey (easyaspi314) <[email protected]>
+//   Sebastian Pop <[email protected]>
+//   Developer Ecosystem Engineering <[email protected]>
+//   Danila Kutenin <[email protected]>
+//   François Turban (JishinMaster) <[email protected]>
+//   Pei-Hsuan Hung <[email protected]>
+//   Yang-Hao Yuan <[email protected]>
+//   Syoyo Fujita <[email protected]>
+//   Brecht Van Lommel <[email protected]>
+
+/*
+ * sse2neon is freely redistributable under the MIT License.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Tunable configurations */
+
+/* Enable precise implementation of math operations
+ * This would slow down the computation a bit, but gives consistent result with
+ * x86 SSE2. (e.g. would solve a hole or NaN pixel in the rendering result)
+ */
+/* _mm_min_ps and _mm_max_ps */
+#ifndef SSE2NEON_PRECISE_MINMAX
+#define SSE2NEON_PRECISE_MINMAX (0)
+#endif
+/* _mm_rcp_ps and _mm_div_ps */
+#ifndef SSE2NEON_PRECISE_DIV
+#define SSE2NEON_PRECISE_DIV (0)
+#endif
+/* _mm_sqrt_ps and _mm_rsqrt_ps */
+#ifndef SSE2NEON_PRECISE_SQRT
+#define SSE2NEON_PRECISE_SQRT (0)
+#endif
+#ifndef SSE2NEON_PRECISE_RSQRT
+#define SSE2NEON_PRECISE_RSQRT (0)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma push_macro("FORCE_INLINE")
+#pragma push_macro("ALIGN_STRUCT")
+#define FORCE_INLINE static inline __attribute__((always_inline))
+#define ALIGN_STRUCT(x) __attribute__((aligned(x)))
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#error "Macro name collisions may happen with unsupported compiler."
+#ifdef FORCE_INLINE
+#undef FORCE_INLINE
+#endif
+#define FORCE_INLINE static inline
+#ifndef ALIGN_STRUCT
+#define ALIGN_STRUCT(x) __declspec(align(x))
+#endif
+#endif
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Architecture-specific build options */
+/* FIXME: #pragma GCC push_options is only available on GCC */
+#if defined(__GNUC__)
+#if defined(__arm__) && __ARM_ARCH == 7
+/* According to ARM C Language Extensions Architecture specification,
+ * __ARM_NEON is defined to a value indicating the Advanced SIMD (NEON)
+ * architecture supported.
+ */
+#if !defined(__ARM_NEON) || !defined(__ARM_NEON__)
+#error "You must enable NEON instructions (e.g. -mfpu=neon) to use SSE2NEON."
+#endif
+#if !defined(__clang__)
+#pragma GCC push_options
+#pragma GCC target("fpu=neon")
+#endif
+#elif defined(__aarch64__)
+#if !defined(__clang__)
+#pragma GCC push_options
+#pragma GCC target("+simd")
+#endif
+#else
+#error "Unsupported target. Must be either ARMv7-A+NEON or ARMv8-A."
+#endif
+#endif
+
+#include <arm_neon.h>
+
+/* Rounding functions require either Aarch64 instructions or libm failback */
+#if !defined(__aarch64__)
+#include <math.h>
+#endif
+
+/* "__has_builtin" can be used to query support for built-in functions
+ * provided by gcc/clang and other compilers that support it.
+ */
+#ifndef __has_builtin /* GCC prior to 10 or non-clang compilers */
+/* Compatibility with gcc <= 9 */
+#if __GNUC__ <= 9
+#define __has_builtin(x) HAS##x
+#define HAS__builtin_popcount 1
+#define HAS__builtin_popcountll 1
+#else
+#define __has_builtin(x) 0
+#endif
+#endif
+
+/**
+ * MACRO for shuffle parameter for _mm_shuffle_ps().
+ * Argument fp3 is a digit[0123] that represents the fp from argument "b"
+ * of mm_shuffle_ps that will be placed in fp3 of result. fp2 is the same
+ * for fp2 in result. fp1 is a digit[0123] that represents the fp from
+ * argument "a" of mm_shuffle_ps that will be places in fp1 of result.
+ * fp0 is the same for fp0 of result.
+ */
+#define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \
+    (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0)))
+
+/* Rounding mode macros. */
+#define _MM_FROUND_TO_NEAREST_INT 0x00
+#define _MM_FROUND_TO_NEG_INF 0x01
+#define _MM_FROUND_TO_POS_INF 0x02
+#define _MM_FROUND_TO_ZERO 0x03
+#define _MM_FROUND_CUR_DIRECTION 0x04
+#define _MM_FROUND_NO_EXC 0x08
+#define _MM_ROUND_NEAREST 0x0000
+#define _MM_ROUND_DOWN 0x2000
+#define _MM_ROUND_UP 0x4000
+#define _MM_ROUND_TOWARD_ZERO 0x6000
+
+/* indicate immediate constant argument in a given range */
+#define __constrange(a, b) const
+
+/* A few intrinsics accept traditional data types like ints or floats, but
+ * most operate on data types that are specific to SSE.
+ * If a vector type ends in d, it contains doubles, and if it does not have
+ * a suffix, it contains floats. An integer vector type can contain any type
+ * of integer, from chars to shorts to unsigned long longs.
+ */
+typedef int64x1_t __m64;
+typedef float32x4_t __m128; /* 128-bit vector containing 4 floats */
+// On ARM 32-bit architecture, the float64x2_t is not supported.
+// The data type __m128d should be represented in a different way for related
+// intrinsic conversion.
+#if defined(__aarch64__)
+typedef float64x2_t __m128d; /* 128-bit vector containing 2 doubles */
+#else
+typedef float32x4_t __m128d;
+#endif
+typedef int64x2_t __m128i; /* 128-bit vector containing integers */
+
+/* type-safe casting between types */
+
+#define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x)
+#define vreinterpretq_m128_f32(x) (x)
+#define vreinterpretq_m128_f64(x) vreinterpretq_f32_f64(x)
+
+#define vreinterpretq_m128_u8(x) vreinterpretq_f32_u8(x)
+#define vreinterpretq_m128_u16(x) vreinterpretq_f32_u16(x)
+#define vreinterpretq_m128_u32(x) vreinterpretq_f32_u32(x)
+#define vreinterpretq_m128_u64(x) vreinterpretq_f32_u64(x)
+
+#define vreinterpretq_m128_s8(x) vreinterpretq_f32_s8(x)
+#define vreinterpretq_m128_s16(x) vreinterpretq_f32_s16(x)
+#define vreinterpretq_m128_s32(x) vreinterpretq_f32_s32(x)
+#define vreinterpretq_m128_s64(x) vreinterpretq_f32_s64(x)
+
+#define vreinterpretq_f16_m128(x) vreinterpretq_f16_f32(x)
+#define vreinterpretq_f32_m128(x) (x)
+#define vreinterpretq_f64_m128(x) vreinterpretq_f64_f32(x)
+
+#define vreinterpretq_u8_m128(x) vreinterpretq_u8_f32(x)
+#define vreinterpretq_u16_m128(x) vreinterpretq_u16_f32(x)
+#define vreinterpretq_u32_m128(x) vreinterpretq_u32_f32(x)
+#define vreinterpretq_u64_m128(x) vreinterpretq_u64_f32(x)
+
+#define vreinterpretq_s8_m128(x) vreinterpretq_s8_f32(x)
+#define vreinterpretq_s16_m128(x) vreinterpretq_s16_f32(x)
+#define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x)
+#define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x)
+
+#define vreinterpretq_m128i_s8(x) vreinterpretq_s64_s8(x)
+#define vreinterpretq_m128i_s16(x) vreinterpretq_s64_s16(x)
+#define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x)
+#define vreinterpretq_m128i_s64(x) (x)
+
+#define vreinterpretq_m128i_u8(x) vreinterpretq_s64_u8(x)
+#define vreinterpretq_m128i_u16(x) vreinterpretq_s64_u16(x)
+#define vreinterpretq_m128i_u32(x) vreinterpretq_s64_u32(x)
+#define vreinterpretq_m128i_u64(x) vreinterpretq_s64_u64(x)
+
+#define vreinterpretq_f32_m128i(x) vreinterpretq_f32_s64(x)
+#define vreinterpretq_f64_m128i(x) vreinterpretq_f64_s64(x)
+
+#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s64(x)
+#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s64(x)
+#define vreinterpretq_s32_m128i(x) vreinterpretq_s32_s64(x)
+#define vreinterpretq_s64_m128i(x) (x)
+
+#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s64(x)
+#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s64(x)
+#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s64(x)
+#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s64(x)
+
+#define vreinterpret_m64_s8(x) vreinterpret_s64_s8(x)
+#define vreinterpret_m64_s16(x) vreinterpret_s64_s16(x)
+#define vreinterpret_m64_s32(x) vreinterpret_s64_s32(x)
+#define vreinterpret_m64_s64(x) (x)
+
+#define vreinterpret_m64_u8(x) vreinterpret_s64_u8(x)
+#define vreinterpret_m64_u16(x) vreinterpret_s64_u16(x)
+#define vreinterpret_m64_u32(x) vreinterpret_s64_u32(x)
+#define vreinterpret_m64_u64(x) vreinterpret_s64_u64(x)
+
+#define vreinterpret_m64_f16(x) vreinterpret_s64_f16(x)
+#define vreinterpret_m64_f32(x) vreinterpret_s64_f32(x)
+#define vreinterpret_m64_f64(x) vreinterpret_s64_f64(x)
+
+#define vreinterpret_u8_m64(x) vreinterpret_u8_s64(x)
+#define vreinterpret_u16_m64(x) vreinterpret_u16_s64(x)
+#define vreinterpret_u32_m64(x) vreinterpret_u32_s64(x)
+#define vreinterpret_u64_m64(x) vreinterpret_u64_s64(x)
+
+#define vreinterpret_s8_m64(x) vreinterpret_s8_s64(x)
+#define vreinterpret_s16_m64(x) vreinterpret_s16_s64(x)
+#define vreinterpret_s32_m64(x) vreinterpret_s32_s64(x)
+#define vreinterpret_s64_m64(x) (x)
+
+#define vreinterpret_f32_m64(x) vreinterpret_f32_s64(x)
+
+#if defined(__aarch64__)
+#define vreinterpretq_m128d_s32(x) vreinterpretq_f64_s32(x)
+#define vreinterpretq_m128d_s64(x) vreinterpretq_f64_s64(x)
+
+#define vreinterpretq_m128d_u64(x) vreinterpretq_f64_u64(x)
+
+#define vreinterpretq_m128d_f32(x) vreinterpretq_f64_f32(x)
+#define vreinterpretq_m128d_f64(x) (x)
+
+#define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f64(x)
+
+#define vreinterpretq_u64_m128d(x) vreinterpretq_u64_f64(x)
+
+#define vreinterpretq_f64_m128d(x) (x)
+#define vreinterpretq_f32_m128d(x) vreinterpretq_f32_f64(x)
+#else
+#define vreinterpretq_m128d_s32(x) vreinterpretq_f32_s32(x)
+#define vreinterpretq_m128d_s64(x) vreinterpretq_f32_s64(x)
+
+#define vreinterpretq_m128d_u32(x) vreinterpretq_f32_u32(x)
+#define vreinterpretq_m128d_u64(x) vreinterpretq_f32_u64(x)
+
+#define vreinterpretq_m128d_f32(x) (x)
+
+#define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f32(x)
+
+#define vreinterpretq_u32_m128d(x) vreinterpretq_u32_f32(x)
+#define vreinterpretq_u64_m128d(x) vreinterpretq_u64_f32(x)
+
+#define vreinterpretq_f32_m128d(x) (x)
+#endif
+
+// A struct is defined in this header file called 'SIMDVec' which can be used
+// by applications which attempt to access the contents of an _m128 struct
+// directly.  It is important to note that accessing the __m128 struct directly
+// is bad coding practice by Microsoft: @see:
+// https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx
+//
+// However, some legacy source code may try to access the contents of an __m128
+// struct directly so the developer can use the SIMDVec as an alias for it.  Any
+// casting must be done manually by the developer, as you cannot cast or
+// otherwise alias the base NEON data type for intrinsic operations.
+//
+// union intended to allow direct access to an __m128 variable using the names
+// that the MSVC compiler provides.  This union should really only be used when
+// trying to access the members of the vector as integer values.  GCC/clang
+// allow native access to the float members through a simple array access
+// operator (in C since 4.6, in C++ since 4.8).
+//
+// Ideally direct accesses to SIMD vectors should not be used since it can cause
+// a performance hit.  If it really is needed however, the original __m128
+// variable can be aliased with a pointer to this union and used to access
+// individual components.  The use of this union should be hidden behind a macro
+// that is used throughout the codebase to access the members instead of always
+// declaring this type of variable.
+typedef union ALIGN_STRUCT(16) SIMDVec {
+    float m128_f32[4];     // as floats - DON'T USE. Added for convenience.
+    int8_t m128_i8[16];    // as signed 8-bit integers.
+    int16_t m128_i16[8];   // as signed 16-bit integers.
+    int32_t m128_i32[4];   // as signed 32-bit integers.
+    int64_t m128_i64[2];   // as signed 64-bit integers.
+    uint8_t m128_u8[16];   // as unsigned 8-bit integers.
+    uint16_t m128_u16[8];  // as unsigned 16-bit integers.
+    uint32_t m128_u32[4];  // as unsigned 32-bit integers.
+    uint64_t m128_u64[2];  // as unsigned 64-bit integers.
+} SIMDVec;
+
+// casting using SIMDVec
+#define vreinterpretq_nth_u64_m128i(x, n) (((SIMDVec *) &x)->m128_u64[n])
+#define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n])
+#define vreinterpretq_nth_u8_m128i(x, n) (((SIMDVec *) &x)->m128_u8[n])
+
+/* Backwards compatibility for compilers with lack of specific type support */
+
+// Older gcc does not define vld1q_u8_x4 type
+#if defined(__GNUC__) && !defined(__clang__) &&   \
+    ((__GNUC__ == 10 && (__GNUC_MINOR__ <= 1)) || \
+     (__GNUC__ == 9 && (__GNUC_MINOR__ <= 3)) ||  \
+     (__GNUC__ == 8 && (__GNUC_MINOR__ <= 4)) || __GNUC__ <= 7)
+FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p)
+{
+    uint8x16x4_t ret;
+    ret.val[0] = vld1q_u8(p + 0);
+    ret.val[1] = vld1q_u8(p + 16);
+    ret.val[2] = vld1q_u8(p + 32);
+    ret.val[3] = vld1q_u8(p + 48);
+    return ret;
+}
+#else
+// Wraps vld1q_u8_x4
+FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p)
+{
+    return vld1q_u8_x4(p);
+}
+#endif
+
+/* Function Naming Conventions
+ * The naming convention of SSE intrinsics is straightforward. A generic SSE
+ * intrinsic function is given as follows:
+ *   _mm_<name>_<data_type>
+ *
+ * The parts of this format are given as follows:
+ * 1. <name> describes the operation performed by the intrinsic
+ * 2. <data_type> identifies the data type of the function's primary arguments
+ *
+ * This last part, <data_type>, is a little complicated. It identifies the
+ * content of the input values, and can be set to any of the following values:
+ * + ps - vectors contain floats (ps stands for packed single-precision)
+ * + pd - vectors cantain doubles (pd stands for packed double-precision)
+ * + epi8/epi16/epi32/epi64 - vectors contain 8-bit/16-bit/32-bit/64-bit
+ *                            signed integers
+ * + epu8/epu16/epu32/epu64 - vectors contain 8-bit/16-bit/32-bit/64-bit
+ *                            unsigned integers
+ * + si128 - unspecified 128-bit vector or 256-bit vector
+ * + m128/m128i/m128d - identifies input vector types when they are different
+ *                      than the type of the returned vector
+ *
+ * For example, _mm_setzero_ps. The _mm implies that the function returns
+ * a 128-bit vector. The _ps at the end implies that the argument vectors
+ * contain floats.
+ *
+ * A complete example: Byte Shuffle - pshufb (_mm_shuffle_epi8)
+ *   // Set packed 16-bit integers. 128 bits, 8 short, per 16 bits
+ *   __m128i v_in = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
+ *   // Set packed 8-bit integers
+ *   // 128 bits, 16 chars, per 8 bits
+ *   __m128i v_perm = _mm_setr_epi8(1, 0,  2,  3, 8, 9, 10, 11,
+ *                                  4, 5, 12, 13, 6, 7, 14, 15);
+ *   // Shuffle packed 8-bit integers
+ *   __m128i v_out = _mm_shuffle_epi8(v_in, v_perm); // pshufb
+ *
+ * Data (Number, Binary, Byte Index):
+    +------+------+-------------+------+------+-------------+
+    |      1      |      2      |      3      |      4      | Number
+    +------+------+------+------+------+------+------+------+
+    | 0000 | 0001 | 0000 | 0010 | 0000 | 0011 | 0000 | 0100 | Binary
+    +------+------+------+------+------+------+------+------+
+    |    0 |    1 |    2 |    3 |    4 |    5 |    6 |    7 | Index
+    +------+------+------+------+------+------+------+------+
+
+    +------+------+------+------+------+------+------+------+
+    |      5      |      6      |      7      |      8      | Number
+    +------+------+------+------+------+------+------+------+
+    | 0000 | 0101 | 0000 | 0110 | 0000 | 0111 | 0000 | 1000 | Binary
+    +------+------+------+------+------+------+------+------+
+    |    8 |    9 |   10 |   11 |   12 |   13 |   14 |   15 | Index
+    +------+------+------+------+------+------+------+------+
+ * Index (Byte Index):
+    +------+------+------+------+------+------+------+------+
+    |    1 |    0 |    2 |    3 |    8 |    9 |   10 |   11 |
+    +------+------+------+------+------+------+------+------+
+
+    +------+------+------+------+------+------+------+------+
+    |    4 |    5 |   12 |   13 |    6 |    7 |   14 |   15 |
+    +------+------+------+------+------+------+------+------+
+ * Result:
+    +------+------+------+------+------+------+------+------+
+    |    1 |    0 |    2 |    3 |    8 |    9 |   10 |   11 | Index
+    +------+------+------+------+------+------+------+------+
+    | 0001 | 0000 | 0000 | 0010 | 0000 | 0101 | 0000 | 0110 | Binary
+    +------+------+------+------+------+------+------+------+
+    |     256     |      2      |      5      |      6      | Number
+    +------+------+------+------+------+------+------+------+
+
+    +------+------+------+------+------+------+------+------+
+    |    4 |    5 |   12 |   13 |    6 |    7 |   14 |   15 | Index
+    +------+------+------+------+------+------+------+------+
+    | 0000 | 0011 | 0000 | 0111 | 0000 | 0100 | 0000 | 1000 | Binary
+    +------+------+------+------+------+------+------+------+
+    |      3      |      7      |      4      |      8      | Number
+    +------+------+------+------+------+------+-------------+
+ */
+
+/* Set/get methods */
+
+/* Constants for use with _mm_prefetch.  */
+enum _mm_hint {
+    _MM_HINT_NTA = 0,  /* load data to L1 and L2 cache, mark it as NTA */
+    _MM_HINT_T0 = 1,   /* load data to L1 and L2 cache */
+    _MM_HINT_T1 = 2,   /* load data to L2 cache only */
+    _MM_HINT_T2 = 3,   /* load data to L2 cache only, mark it as NTA */
+    _MM_HINT_ENTA = 4, /* exclusive version of _MM_HINT_NTA */
+    _MM_HINT_ET0 = 5,  /* exclusive version of _MM_HINT_T0 */
+    _MM_HINT_ET1 = 6,  /* exclusive version of _MM_HINT_T1 */
+    _MM_HINT_ET2 = 7   /* exclusive version of _MM_HINT_T2 */
+};
+
+// Loads one cache line of data from address p to a location closer to the
+// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx
+FORCE_INLINE void _mm_prefetch(const void *p, int i)
+{
+    (void) i;
+    __builtin_prefetch(p);
+}
+
+// Pause the processor. This is typically used in spin-wait loops and depending
+// on the x86 processor typical values are in the 40-100 cycle range. The
+// 'yield' instruction isn't a good fit beacuse it's effectively a nop on most
+// Arm cores. Experience with several databases has shown has shown an 'isb' is
+// a reasonable approximation.
+FORCE_INLINE void _mm_pause()
+{
+    __asm__ __volatile__("isb\n");
+}
+
+// Copy the lower single-precision (32-bit) floating-point element of a to dst.
+//
+//   dst[31:0] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32
+FORCE_INLINE float _mm_cvtss_f32(__m128 a)
+{
+    return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in b to a
+// double-precision (64-bit) floating-point element, store the result in the
+// lower element of dst, and copy the upper element from a to the upper element
+// of dst.
+//
+//   dst[63:0] := Convert_FP32_To_FP64(b[31:0])
+//   dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_sd
+FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b)
+{
+    double d = (double) vgetq_lane_f32(vreinterpretq_f32_m128(b), 0);
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vsetq_lane_f64(d, vreinterpretq_f64_m128d(a), 0));
+#else
+    return vreinterpretq_m128d_s64(
+        vsetq_lane_s64(*(int64_t *) &d, vreinterpretq_s64_m128d(a), 0));
+#endif
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer, and store the result in dst.
+//
+//   dst[31:0] := Convert_FP32_To_Int32(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32
+#define _mm_cvtss_si32(a) _mm_cvt_ss2si(a)
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 64-bit integer, and store the result in dst.
+//
+//   dst[63:0] := Convert_FP32_To_Int64(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64
+FORCE_INLINE int _mm_cvtss_si64(__m128 a)
+{
+#if defined(__aarch64__)
+    return vgetq_lane_s64(
+        vreinterpretq_s64_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a))), 0);
+#else
+    float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+    float32_t diff = data - floor(data);
+    if (diff > 0.5)
+        return (int64_t) ceil(data);
+    if (unlikely(diff == 0.5)) {
+        int64_t f = (int64_t) floor(data);
+        int64_t c = (int64_t) ceil(data);
+        return c & 1 ? f : c;
+    }
+    return (int64_t) floor(data);
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers with truncation, and store the results in dst.
+//
+//   FOR j := 0 to 1
+//      i := 32*j
+//      dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi
+FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a)
+{
+    return vreinterpret_m64_s32(
+        vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a))));
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer with truncation, and store the result in dst.
+//
+//   dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si
+FORCE_INLINE int _mm_cvtt_ss2si(__m128 a)
+{
+    return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0);
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers with truncation, and store the results in dst.
+//
+//   FOR j := 0 to 1
+//      i := 32*j
+//      dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32
+#define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a)
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer with truncation, and store the result in dst.
+//
+//   dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32
+#define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a)
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 64-bit integer with truncation, and store the result in dst.
+//
+//   dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64
+FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a)
+{
+    return vgetq_lane_s64(
+        vmovl_s32(vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))), 0);
+}
+
+// Sets the 128-bit value to zero
+// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_setzero_si128(void)
+{
+    return vreinterpretq_m128i_s32(vdupq_n_s32(0));
+}
+
+// Clears the four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setzero_ps(void)
+{
+    return vreinterpretq_m128_f32(vdupq_n_f32(0));
+}
+
+// Return vector of type __m128d with all elements set to zero.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd
+FORCE_INLINE __m128d _mm_setzero_pd(void)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vdupq_n_f64(0));
+#else
+    return vreinterpretq_m128d_f32(vdupq_n_f32(0));
+#endif
+}
+
+// Sets the four single-precision, floating-point values to w.
+//
+//   r0 := r1 := r2 := r3 := w
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set1_ps(float _w)
+{
+    return vreinterpretq_m128_f32(vdupq_n_f32(_w));
+}
+
+// Sets the four single-precision, floating-point values to w.
+// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps1(float _w)
+{
+    return vreinterpretq_m128_f32(vdupq_n_f32(_w));
+}
+
+// Sets the four single-precision, floating-point values to the four inputs.
+// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x)
+{
+    float ALIGN_STRUCT(16) data[4] = {x, y, z, w};
+    return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Copy single-precision (32-bit) floating-point element a to the lower element
+// of dst, and zero the upper 3 elements.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss
+FORCE_INLINE __m128 _mm_set_ss(float a)
+{
+    float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0};
+    return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Sets the four single-precision, floating-point values to the four inputs in
+// reverse order.
+// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x)
+{
+    float ALIGN_STRUCT(16) data[4] = {w, z, y, x};
+    return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Sets the 8 signed 16-bit integer values in reverse order.
+//
+// Return Value
+//   r0 := w0
+//   r1 := w1
+//   ...
+//   r7 := w7
+FORCE_INLINE __m128i _mm_setr_epi16(short w0,
+                                    short w1,
+                                    short w2,
+                                    short w3,
+                                    short w4,
+                                    short w5,
+                                    short w6,
+                                    short w7)
+{
+    int16_t ALIGN_STRUCT(16) data[8] = {w0, w1, w2, w3, w4, w5, w6, w7};
+    return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data));
+}
+
+// Sets the 4 signed 32-bit integer values in reverse order
+// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0)
+{
+    int32_t ALIGN_STRUCT(16) data[4] = {i3, i2, i1, i0};
+    return vreinterpretq_m128i_s32(vld1q_s32(data));
+}
+
+// Set packed 64-bit integers in dst with the supplied values in reverse order.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64
+FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0)
+{
+    return vreinterpretq_m128i_s64(vcombine_s64(e1, e0));
+}
+
+// Sets the 16 signed 8-bit integer values to b.
+//
+//   r0 := b
+//   r1 := b
+//   ...
+//   r15 := b
+//
+// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi8(signed char w)
+{
+    return vreinterpretq_m128i_s8(vdupq_n_s8(w));
+}
+
+// Broadcast double-precision (64-bit) floating-point value a to all elements of
+// dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_pd
+FORCE_INLINE __m128d _mm_set1_pd(double d)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vdupq_n_f64(d));
+#else
+    return vreinterpretq_m128d_s64(vdupq_n_s64(*(int64_t *) &d));
+#endif
+}
+
+// Sets the 8 signed 16-bit integer values to w.
+//
+//   r0 := w
+//   r1 := w
+//   ...
+//   r7 := w
+//
+// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set1_epi16(short w)
+{
+    return vreinterpretq_m128i_s16(vdupq_n_s16(w));
+}
+
+// Sets the 16 signed 8-bit integer values.
+// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set_epi8(signed char b15,
+                                  signed char b14,
+                                  signed char b13,
+                                  signed char b12,
+                                  signed char b11,
+                                  signed char b10,
+                                  signed char b9,
+                                  signed char b8,
+                                  signed char b7,
+                                  signed char b6,
+                                  signed char b5,
+                                  signed char b4,
+                                  signed char b3,
+                                  signed char b2,
+                                  signed char b1,
+                                  signed char b0)
+{
+    int8_t ALIGN_STRUCT(16)
+        data[16] = {(int8_t) b0,  (int8_t) b1,  (int8_t) b2,  (int8_t) b3,
+                    (int8_t) b4,  (int8_t) b5,  (int8_t) b6,  (int8_t) b7,
+                    (int8_t) b8,  (int8_t) b9,  (int8_t) b10, (int8_t) b11,
+                    (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};
+    return (__m128i) vld1q_s8(data);
+}
+
+// Sets the 8 signed 16-bit integer values.
+// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set_epi16(short i7,
+                                   short i6,
+                                   short i5,
+                                   short i4,
+                                   short i3,
+                                   short i2,
+                                   short i1,
+                                   short i0)
+{
+    int16_t ALIGN_STRUCT(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7};
+    return vreinterpretq_m128i_s16(vld1q_s16(data));
+}
+
+// Sets the 16 signed 8-bit integer values in reverse order.
+// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_setr_epi8(signed char b0,
+                                   signed char b1,
+                                   signed char b2,
+                                   signed char b3,
+                                   signed char b4,
+                                   signed char b5,
+                                   signed char b6,
+                                   signed char b7,
+                                   signed char b8,
+                                   signed char b9,
+                                   signed char b10,
+                                   signed char b11,
+                                   signed char b12,
+                                   signed char b13,
+                                   signed char b14,
+                                   signed char b15)
+{
+    int8_t ALIGN_STRUCT(16)
+        data[16] = {(int8_t) b0,  (int8_t) b1,  (int8_t) b2,  (int8_t) b3,
+                    (int8_t) b4,  (int8_t) b5,  (int8_t) b6,  (int8_t) b7,
+                    (int8_t) b8,  (int8_t) b9,  (int8_t) b10, (int8_t) b11,
+                    (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};
+    return (__m128i) vld1q_s8(data);
+}
+
+// Sets the 4 signed 32-bit integer values to i.
+//
+//   r0 := i
+//   r1 := i
+//   r2 := i
+//   r3 := I
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi32(int _i)
+{
+    return vreinterpretq_m128i_s32(vdupq_n_s32(_i));
+}
+
+// Sets the 2 signed 64-bit integer values to i.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/whtfzhzk(v=vs.100)
+FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i)
+{
+    return vreinterpretq_m128i_s64(vdupq_n_s64((int64_t) _i));
+}
+
+// Sets the 2 signed 64-bit integer values to i.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x
+FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i)
+{
+    return vreinterpretq_m128i_s64(vdupq_n_s64(_i));
+}
+
+// Sets the 4 signed 32-bit integer values.
+// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
+{
+    int32_t ALIGN_STRUCT(16) data[4] = {i0, i1, i2, i3};
+    return vreinterpretq_m128i_s32(vld1q_s32(data));
+}
+
+// Returns the __m128i structure with its two 64-bit integer values
+// initialized to the values of the two 64-bit integers passed in.
+// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2)
+{
+    return vreinterpretq_m128i_s64(
+        vcombine_s64(vcreate_s64(i2), vcreate_s64(i1)));
+}
+
+// Returns the __m128i structure with its two 64-bit integer values
+// initialized to the values of the two 64-bit integers passed in.
+// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_set_epi64(__m64 i1, __m64 i2)
+{
+    return _mm_set_epi64x((int64_t) i1, (int64_t) i2);
+}
+
+// Set packed double-precision (64-bit) floating-point elements in dst with the
+// supplied values.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd
+FORCE_INLINE __m128d _mm_set_pd(double e1, double e0)
+{
+    double ALIGN_STRUCT(16) data[2] = {e0, e1};
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vld1q_f64((float64_t *) data));
+#else
+    return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) data));
+#endif
+}
+
+// Set packed double-precision (64-bit) floating-point elements in dst with the
+// supplied values in reverse order.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_pd
+FORCE_INLINE __m128d _mm_setr_pd(double e1, double e0)
+{
+    return _mm_set_pd(e0, e1);
+}
+
+// Copy double-precision (64-bit) floating-point element a to the lower element
+// of dst, and zero the upper element.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_sd
+FORCE_INLINE __m128d _mm_set_sd(double a)
+{
+    return _mm_set_pd(0, a);
+}
+
+// Broadcast double-precision (64-bit) floating-point value a to all elements of
+// dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd1
+#define _mm_set_pd1 _mm_set1_pd
+
+// Stores four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ps(float *p, __m128 a)
+{
+    vst1q_f32(p, vreinterpretq_f32_m128(a));
+}
+
+// Store the lower single-precision (32-bit) floating-point element from a into
+// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+//
+//   MEM[mem_addr+31:mem_addr] := a[31:0]
+//   MEM[mem_addr+63:mem_addr+32] := a[31:0]
+//   MEM[mem_addr+95:mem_addr+64] := a[31:0]
+//   MEM[mem_addr+127:mem_addr+96] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_ps1
+FORCE_INLINE void _mm_store_ps1(float *p, __m128 a)
+{
+    float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+    vst1q_f32(p, vdupq_n_f32(a0));
+}
+
+// Store the lower single-precision (32-bit) floating-point element from a into
+// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+//
+//   MEM[mem_addr+31:mem_addr] := a[31:0]
+//   MEM[mem_addr+63:mem_addr+32] := a[31:0]
+//   MEM[mem_addr+95:mem_addr+64] := a[31:0]
+//   MEM[mem_addr+127:mem_addr+96] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps
+#define _mm_store1_ps _mm_store_ps1
+
+// Store 4 single-precision (32-bit) floating-point elements from a into memory
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+//   MEM[mem_addr+31:mem_addr] := a[127:96]
+//   MEM[mem_addr+63:mem_addr+32] := a[95:64]
+//   MEM[mem_addr+95:mem_addr+64] := a[63:32]
+//   MEM[mem_addr+127:mem_addr+96] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps
+FORCE_INLINE void _mm_storer_ps(float *p, __m128 a)
+{
+    float32x4_t tmp = vrev64q_f32(vreinterpretq_f32_m128(a));
+    float32x4_t rev = vextq_f32(tmp, tmp, 2);
+    vst1q_f32(p, rev);
+}
+
+// Stores four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a)
+{
+    vst1q_f32(p, vreinterpretq_f32_m128(a));
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p.
+// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a)
+{
+    vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p.
+// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a)
+{
+    vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));
+}
+
+// Stores the lower single - precision, floating - point value.
+// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ss(float *p, __m128 a)
+{
+    vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0);
+}
+
+// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point
+// elements) from a into memory. mem_addr must be aligned on a 16-byte boundary
+// or a general-protection exception may be generated.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd
+FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+    vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(a));
+#else
+    vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(a));
+#endif
+}
+
+// Store the upper double-precision (64-bit) floating-point element from a into
+// memory.
+//
+//   MEM[mem_addr+63:mem_addr] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeh_pd
+FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+    vst1_f64((float64_t *) mem_addr, vget_high_f64(vreinterpretq_f64_m128d(a)));
+#else
+    vst1_f32((float32_t *) mem_addr, vget_high_f32(vreinterpretq_f32_m128d(a)));
+#endif
+}
+
+// Store the lower double-precision (64-bit) floating-point element from a into
+// memory.
+//
+//   MEM[mem_addr+63:mem_addr] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storel_pd
+FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+    vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a)));
+#else
+    vst1_f32((float32_t *) mem_addr, vget_low_f32(vreinterpretq_f32_m128d(a)));
+#endif
+}
+
+// Store 2 double-precision (64-bit) floating-point elements from a into memory
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+//   MEM[mem_addr+63:mem_addr] := a[127:64]
+//   MEM[mem_addr+127:mem_addr+64] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_pd
+FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a)
+{
+    float32x4_t f = vreinterpretq_f32_m128d(a);
+    _mm_store_pd(mem_addr, vreinterpretq_m128d_f32(vextq_f32(f, f, 2)));
+}
+
+// Store the lower double-precision (64-bit) floating-point element from a into
+// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd1
+FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+    float64x1_t a_low = vget_low_f64(vreinterpretq_f64_m128d(a));
+    vst1q_f64((float64_t *) mem_addr,
+              vreinterpretq_f64_m128d(vcombine_f64(a_low, a_low)));
+#else
+    float32x2_t a_low = vget_low_f32(vreinterpretq_f32_m128d(a));
+    vst1q_f32((float32_t *) mem_addr,
+              vreinterpretq_f32_m128d(vcombine_f32(a_low, a_low)));
+#endif
+}
+
+// Store the lower double-precision (64-bit) floating-point element from a into
+// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=9,526,5601&text=_mm_store1_pd
+#define _mm_store1_pd _mm_store_pd1
+
+// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point
+// elements) from a into memory. mem_addr does not need to be aligned on any
+// particular boundary.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd
+FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a)
+{
+    _mm_store_pd(mem_addr, a);
+}
+
+// Reads the lower 64 bits of b and stores them into the lower 64 bits of a.
+// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b)
+{
+    uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a));
+    uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b));
+    *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi));
+}
+
+// Stores the lower two single-precision floating point values of a to the
+// address p.
+//
+//   *p0 := a0
+//   *p1 := a1
+//
+// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx
+FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a)
+{
+    *p = vreinterpret_m64_f32(vget_low_f32(a));
+}
+
+// Stores the upper two single-precision, floating-point values of a to the
+// address p.
+//
+//   *p0 := a2
+//   *p1 := a3
+//
+// https://msdn.microsoft.com/en-us/library/a7525fs8(v%3dvs.90).aspx
+FORCE_INLINE void _mm_storeh_pi(__m64 *p, __m128 a)
+{
+    *p = vreinterpret_m64_f32(vget_high_f32(a));
+}
+
+// Loads a single single-precision, floating-point value, copying it into all
+// four words
+// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load1_ps(const float *p)
+{
+    return vreinterpretq_m128_f32(vld1q_dup_f32(p));
+}
+
+// Load a single-precision (32-bit) floating-point element from memory into all
+// elements of dst.
+//
+//   dst[31:0] := MEM[mem_addr+31:mem_addr]
+//   dst[63:32] := MEM[mem_addr+31:mem_addr]
+//   dst[95:64] := MEM[mem_addr+31:mem_addr]
+//   dst[127:96] := MEM[mem_addr+31:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1
+#define _mm_load_ps1 _mm_load1_ps
+
+// Sets the lower two single-precision, floating-point values with 64
+// bits of data loaded from the address p; the upper two values are passed
+// through from a.
+//
+// Return Value
+//   r0 := *p0
+//   r1 := *p1
+//   r2 := a2
+//   r3 := a3
+//
+// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p)
+{
+    return vreinterpretq_m128_f32(
+        vcombine_f32(vld1_f32((const float32_t *) p), vget_high_f32(a)));
+}
+
+// Load 4 single-precision (32-bit) floating-point elements from memory into dst
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+//   dst[31:0] := MEM[mem_addr+127:mem_addr+96]
+//   dst[63:32] := MEM[mem_addr+95:mem_addr+64]
+//   dst[95:64] := MEM[mem_addr+63:mem_addr+32]
+//   dst[127:96] := MEM[mem_addr+31:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps
+FORCE_INLINE __m128 _mm_loadr_ps(const float *p)
+{
+    float32x4_t v = vrev64q_f32(vld1q_f32(p));
+    return vreinterpretq_m128_f32(vextq_f32(v, v, 2));
+}
+
+// Sets the upper two single-precision, floating-point values with 64
+// bits of data loaded from the address p; the lower two values are passed
+// through from a.
+//
+//   r0 := a0
+//   r1 := a1
+//   r2 := *p0
+//   r3 := *p1
+//
+// https://msdn.microsoft.com/en-us/library/w92wta0x(v%3dvs.100).aspx
+FORCE_INLINE __m128 _mm_loadh_pi(__m128 a, __m64 const *p)
+{
+    return vreinterpretq_m128_f32(
+        vcombine_f32(vget_low_f32(a), vld1_f32((const float32_t *) p)));
+}
+
+// Loads four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load_ps(const float *p)
+{
+    return vreinterpretq_m128_f32(vld1q_f32(p));
+}
+
+// Loads four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_loadu_ps(const float *p)
+{
+    // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are
+    // equivalent for neon
+    return vreinterpretq_m128_f32(vld1q_f32(p));
+}
+
+// Load unaligned 16-bit integer from memory into the first element of dst.
+//
+//   dst[15:0] := MEM[mem_addr+15:mem_addr]
+//   dst[MAX:16] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16
+FORCE_INLINE __m128i _mm_loadu_si16(const void *p)
+{
+    return vreinterpretq_m128i_s16(
+        vsetq_lane_s16(*(const int16_t *) p, vdupq_n_s16(0), 0));
+}
+
+// Load unaligned 64-bit integer from memory into the first element of dst.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[MAX:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64
+FORCE_INLINE __m128i _mm_loadu_si64(const void *p)
+{
+    return vreinterpretq_m128i_s64(
+        vcombine_s64(vld1_s64((const int64_t *) p), vdup_n_s64(0)));
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into the
+// lower of dst, and zero the upper element. mem_addr does not need to be
+// aligned on any particular boundary.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd
+FORCE_INLINE __m128d _mm_load_sd(const double *p)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vsetq_lane_f64(*p, vdupq_n_f64(0), 0));
+#else
+    const float *fp = (const float *) p;
+    float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], 0, 0};
+    return vreinterpretq_m128d_f32(vld1q_f32(data));
+#endif
+}
+
+// Loads two double-precision from 16-byte aligned memory, floating-point
+// values.
+//
+//   dst[127:0] := MEM[mem_addr+127:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd
+FORCE_INLINE __m128d _mm_load_pd(const double *p)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vld1q_f64(p));
+#else
+    const float *fp = (const float *) p;
+    float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], fp[2], fp[3]};
+    return vreinterpretq_m128d_f32(vld1q_f32(data));
+#endif
+}
+
+// Loads two double-precision from unaligned memory, floating-point values.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd
+FORCE_INLINE __m128d _mm_loadu_pd(const double *p)
+{
+    return _mm_load_pd(p);
+}
+
+// Loads an single - precision, floating - point value into the low word and
+// clears the upper three words.
+// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_load_ss(const float *p)
+{
+    return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0));
+}
+
+// Load 64-bit integer from memory into the first element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_epi64
+FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p)
+{
+    /* Load the lower 64 bits of the value pointed to by p into the
+     * lower 64 bits of the result, zeroing the upper 64 bits of the result.
+     */
+    return vreinterpretq_m128i_s32(
+        vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0)));
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into the
+// lower element of dst, and copy the upper element from a to dst. mem_addr does
+// not need to be aligned on any particular boundary.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd
+FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vcombine_f64(vld1_f64(p), vget_high_f64(vreinterpretq_f64_m128d(a))));
+#else
+    return vreinterpretq_m128d_f32(
+        vcombine_f32(vld1_f32((const float *) p),
+                     vget_high_f32(vreinterpretq_f32_m128d(a))));
+#endif
+}
+
+// Load 2 double-precision (64-bit) floating-point elements from memory into dst
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+//   dst[63:0] := MEM[mem_addr+127:mem_addr+64]
+//   dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd
+FORCE_INLINE __m128d _mm_loadr_pd(const double *p)
+{
+#if defined(__aarch64__)
+    float64x2_t v = vld1q_f64(p);
+    return vreinterpretq_m128d_f64(vextq_f64(v, v, 1));
+#else
+    int64x2_t v = vld1q_s64((const int64_t *) p);
+    return vreinterpretq_m128d_s64(vextq_s64(v, v, 1));
+#endif
+}
+
+// Sets the low word to the single-precision, floating-point value of b
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/35hdzazd(v=vs.100)
+FORCE_INLINE __m128 _mm_move_ss(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32(vgetq_lane_f32(vreinterpretq_f32_m128(b), 0),
+                       vreinterpretq_f32_m128(a), 0));
+}
+
+// Move the lower double-precision (64-bit) floating-point element from b to the
+// lower element of dst, and copy the upper element from a to the upper element
+// of dst.
+//
+//   dst[63:0] := b[63:0]
+//   dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd
+FORCE_INLINE __m128d _mm_move_sd(__m128d a, __m128d b)
+{
+    return vreinterpretq_m128d_f32(
+        vcombine_f32(vget_low_f32(vreinterpretq_f32_m128d(b)),
+                     vget_high_f32(vreinterpretq_f32_m128d(a))));
+}
+
+// Copy the lower 64-bit integer in a to the lower element of dst, and zero the
+// upper element.
+//
+//   dst[63:0] := a[63:0]
+//   dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64
+FORCE_INLINE __m128i _mm_move_epi64(__m128i a)
+{
+    return vreinterpretq_m128i_s64(
+        vsetq_lane_s64(0, vreinterpretq_s64_m128i(a), 1));
+}
+
+// Return vector of type __m128 with undefined elements.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps
+FORCE_INLINE __m128 _mm_undefined_ps(void)
+{
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+    __m128 a;
+    return a;
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+}
+
+/* Logic/Binary operations */
+
+// Computes the bitwise AND-NOT of the four single-precision, floating-point
+// values of a and b.
+//
+//   r0 := ~a0 & b0
+//   r1 := ~a1 & b1
+//   r2 := ~a2 & b2
+//   r3 := ~a3 & b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_s32(
+        vbicq_s32(vreinterpretq_s32_m128(b),
+                  vreinterpretq_s32_m128(a)));  // *NOTE* argument swap
+}
+
+// Compute the bitwise NOT of packed double-precision (64-bit) floating-point
+// elements in a and then AND with b, and store the results in dst.
+//
+//   FOR j := 0 to 1
+// 	     i := j*64
+// 	     dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd
+FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b)
+{
+    // *NOTE* argument swap
+    return vreinterpretq_m128d_s64(
+        vbicq_s64(vreinterpretq_s64_m128d(b), vreinterpretq_s64_m128d(a)));
+}
+
+// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the
+// 128-bit value in a.
+//
+//   r := (~a) & b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vbicq_s32(vreinterpretq_s32_m128i(b),
+                  vreinterpretq_s32_m128i(a)));  // *NOTE* argument swap
+}
+
+// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in
+// b.
+//
+//   r := a & b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the bitwise AND of the four single-precision, floating-point values
+// of a and b.
+//
+//   r0 := a0 & b0
+//   r1 := a1 & b1
+//   r2 := a2 & b2
+//   r3 := a3 & b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_s32(
+        vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Compute the bitwise AND of packed double-precision (64-bit) floating-point
+// elements in a and b, and store the results in dst.
+//
+//   FOR j := 0 to 1
+//     i := j*64
+//     dst[i+63:i] := a[i+63:i] AND b[i+63:i]
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd
+FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b)
+{
+    return vreinterpretq_m128d_s64(
+        vandq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b)));
+}
+
+// Computes the bitwise OR of the four single-precision, floating-point values
+// of a and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_s32(
+        vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Computes bitwise EXOR (exclusive-or) of the four single-precision,
+// floating-point values of a and b.
+// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_s32(
+        veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Compute the bitwise XOR of packed double-precision (64-bit) floating-point
+// elements in a and b, and store the results in dst.
+//
+//   FOR j := 0 to 1
+//      i := j*64
+//      dst[i+63:i] := a[i+63:i] XOR b[i+63:i]
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd
+FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b)
+{
+    return vreinterpretq_m128d_s64(
+        veorq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b)));
+}
+
+// Compute the bitwise OR of packed double-precision (64-bit) floating-point
+// elements in a and b, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_or_pd
+FORCE_INLINE __m128d _mm_or_pd(__m128d a, __m128d b)
+{
+    return vreinterpretq_m128d_s64(
+        vorrq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b)));
+}
+
+// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b.
+//
+//   r := a | b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in
+// b.  https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Duplicate the low double-precision (64-bit) floating-point element from a,
+// and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movedup_pd
+FORCE_INLINE __m128d _mm_movedup_pd(__m128d a)
+{
+#if (__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vdupq_laneq_f64(vreinterpretq_f64_m128d(a), 0));
+#else
+    return vreinterpretq_m128d_u64(
+        vdupq_n_u64(vgetq_lane_u64(vreinterpretq_u64_m128d(a), 0)));
+#endif
+}
+
+// Duplicate odd-indexed single-precision (32-bit) floating-point elements
+// from a, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps
+FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a)
+{
+#if __has_builtin(__builtin_shufflevector)
+    return vreinterpretq_m128_f32(__builtin_shufflevector(
+        vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3));
+#else
+    float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1);
+    float32_t a3 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 3);
+    float ALIGN_STRUCT(16) data[4] = {a1, a1, a3, a3};
+    return vreinterpretq_m128_f32(vld1q_f32(data));
+#endif
+}
+
+// Duplicate even-indexed single-precision (32-bit) floating-point elements
+// from a, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps
+FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a)
+{
+#if __has_builtin(__builtin_shufflevector)
+    return vreinterpretq_m128_f32(__builtin_shufflevector(
+        vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2));
+#else
+    float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+    float32_t a2 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 2);
+    float ALIGN_STRUCT(16) data[4] = {a0, a0, a2, a2};
+    return vreinterpretq_m128_f32(vld1q_f32(data));
+#endif
+}
+
+// Moves the upper two values of B into the lower two values of A.
+//
+//   r3 := a3
+//   r2 := a2
+//   r1 := b3
+//   r0 := b2
+FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B)
+{
+    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A));
+    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B));
+    return vreinterpretq_m128_f32(vcombine_f32(b32, a32));
+}
+
+// Moves the lower two values of B into the upper two values of A.
+//
+//   r3 := b1
+//   r2 := b0
+//   r1 := a1
+//   r0 := a0
+FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B)
+{
+    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A));
+    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B));
+    return vreinterpretq_m128_f32(vcombine_f32(a10, b10));
+}
+
+// Compute the absolute value of packed signed 32-bit integers in a, and store
+// the unsigned results in dst.
+//
+//   FOR j := 0 to 3
+//     i := j*32
+//     dst[i+31:i] := ABS(a[i+31:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32
+FORCE_INLINE __m128i _mm_abs_epi32(__m128i a)
+{
+    return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a)));
+}
+
+// Compute the absolute value of packed signed 16-bit integers in a, and store
+// the unsigned results in dst.
+//
+//   FOR j := 0 to 7
+//     i := j*16
+//     dst[i+15:i] := ABS(a[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16
+FORCE_INLINE __m128i _mm_abs_epi16(__m128i a)
+{
+    return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a)));
+}
+
+// Compute the absolute value of packed signed 8-bit integers in a, and store
+// the unsigned results in dst.
+//
+//   FOR j := 0 to 15
+//     i := j*8
+//     dst[i+7:i] := ABS(a[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8
+FORCE_INLINE __m128i _mm_abs_epi8(__m128i a)
+{
+    return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a)));
+}
+
+// Compute the absolute value of packed signed 32-bit integers in a, and store
+// the unsigned results in dst.
+//
+//   FOR j := 0 to 1
+//     i := j*32
+//     dst[i+31:i] := ABS(a[i+31:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32
+FORCE_INLINE __m64 _mm_abs_pi32(__m64 a)
+{
+    return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a)));
+}
+
+// Compute the absolute value of packed signed 16-bit integers in a, and store
+// the unsigned results in dst.
+//
+//   FOR j := 0 to 3
+//     i := j*16
+//     dst[i+15:i] := ABS(a[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16
+FORCE_INLINE __m64 _mm_abs_pi16(__m64 a)
+{
+    return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a)));
+}
+
+// Compute the absolute value of packed signed 8-bit integers in a, and store
+// the unsigned results in dst.
+//
+//   FOR j := 0 to 7
+//     i := j*8
+//     dst[i+7:i] := ABS(a[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8
+FORCE_INLINE __m64 _mm_abs_pi8(__m64 a)
+{
+    return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a)));
+}
+
+// Concatenate 16-byte blocks in a and b into a 32-byte temporary result, shift
+// the result right by imm8 bytes, and store the low 16 bytes in dst.
+//
+//   tmp[255:0] := ((a[127:0] << 128)[255:0] OR b[127:0]) >> (imm8*8)
+//   dst[127:0] := tmp[127:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_epi8
+#define _mm_alignr_epi8(a, b, imm)                                            \
+    __extension__({                                                           \
+        __m128i ret;                                                          \
+        if (unlikely((imm) >= 32)) {                                          \
+            ret = _mm_setzero_si128();                                        \
+        } else {                                                              \
+            uint8x16_t tmp_low, tmp_high;                                     \
+            if (imm >= 16) {                                                  \
+                const int idx = imm - 16;                                     \
+                tmp_low = vreinterpretq_u8_m128i(a);                          \
+                tmp_high = vdupq_n_u8(0);                                     \
+                ret =                                                         \
+                    vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \
+            } else {                                                          \
+                const int idx = imm;                                          \
+                tmp_low = vreinterpretq_u8_m128i(b);                          \
+                tmp_high = vreinterpretq_u8_m128i(a);                         \
+                ret =                                                         \
+                    vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \
+            }                                                                 \
+        }                                                                     \
+        ret;                                                                  \
+    })
+
+// Concatenate 8-byte blocks in a and b into a 16-byte temporary result, shift
+// the result right by imm8 bytes, and store the low 8 bytes in dst.
+//
+//   tmp[127:0] := ((a[63:0] << 64)[127:0] OR b[63:0]) >> (imm8*8)
+//   dst[63:0] := tmp[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_pi8
+#define _mm_alignr_pi8(a, b, imm)                                           \
+    __extension__({                                                         \
+        __m64 ret;                                                          \
+        if (unlikely((imm) >= 16)) {                                        \
+            ret = vreinterpret_m64_s8(vdup_n_s8(0));                        \
+        } else {                                                            \
+            uint8x8_t tmp_low, tmp_high;                                    \
+            if (imm >= 8) {                                                 \
+                const int idx = imm - 8;                                    \
+                tmp_low = vreinterpret_u8_m64(a);                           \
+                tmp_high = vdup_n_u8(0);                                    \
+                ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \
+            } else {                                                        \
+                const int idx = imm;                                        \
+                tmp_low = vreinterpret_u8_m64(b);                           \
+                tmp_high = vreinterpret_u8_m64(a);                          \
+                ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \
+            }                                                               \
+        }                                                                   \
+        ret;                                                                \
+    })
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of b and places it into the high end of the result.
+FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b)
+{
+    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_f32(vcombine_f32(a32, b10));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in high
+// end of result takes the higher two 32 bit values from b and swaps them and
+// places in low end of result.
+FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b)
+{
+    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+    float32x2_t b23 = vrev64_f32(vget_high_f32(vreinterpretq_f32_m128(b)));
+    return vreinterpretq_m128_f32(vcombine_f32(a01, b23));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b)
+{
+    float32x2_t a21 = vget_high_f32(
+        vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));
+    float32x2_t b03 = vget_low_f32(
+        vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));
+    return vreinterpretq_m128_f32(vcombine_f32(a21, b03));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b)
+{
+    float32x2_t a03 = vget_low_f32(
+        vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));
+    float32x2_t b21 = vget_high_f32(
+        vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));
+    return vreinterpretq_m128_f32(vcombine_f32(a03, b21));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b)
+{
+    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_f32(vcombine_f32(a10, b10));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b)
+{
+    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_f32(vcombine_f32(a01, b10));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b)
+{
+    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+    float32x2_t b01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(b)));
+    return vreinterpretq_m128_f32(vcombine_f32(a01, b01));
+}
+
+// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the
+// high
+FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b)
+{
+    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_f32(vcombine_f32(a10, b32));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b)
+{
+    float32x2_t a11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 1);
+    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+    return vreinterpretq_m128_f32(vcombine_f32(a11, b00));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b)
+{
+    float32x2_t a22 =
+        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);
+    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+    return vreinterpretq_m128_f32(vcombine_f32(a22, b00));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b)
+{
+    float32x2_t a00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 0);
+    float32x2_t b22 =
+        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(b)), 0);
+    return vreinterpretq_m128_f32(vcombine_f32(a00, b22));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b)
+{
+    float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+    float32x2_t a22 =
+        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);
+    float32x2_t a02 = vset_lane_f32(a0, a22, 1); /* TODO: use vzip ?*/
+    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_f32(vcombine_f32(a02, b32));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b)
+{
+    float32x2_t a33 =
+        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 1);
+    float32x2_t b11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 1);
+    return vreinterpretq_m128_f32(vcombine_f32(a33, b11));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b)
+{
+    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+    float32_t b2 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 2);
+    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+    float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+    return vreinterpretq_m128_f32(vcombine_f32(a10, b20));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b)
+{
+    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+    float32_t b2 = vgetq_lane_f32(b, 2);
+    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+    float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+    return vreinterpretq_m128_f32(vcombine_f32(a01, b20));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b)
+{
+    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+    float32_t b2 = vgetq_lane_f32(b, 2);
+    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+    float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+    return vreinterpretq_m128_f32(vcombine_f32(a32, b20));
+}
+
+// NEON does not support a general purpose permute intrinsic
+// Selects four specific single-precision, floating-point values from a and b,
+// based on the mask i.
+//
+// C equivalent:
+//   __m128 _mm_shuffle_ps_default(__m128 a, __m128 b,
+//                                 __constrange(0, 255) int imm) {
+//       __m128 ret;
+//       ret[0] = a[imm        & 0x3];   ret[1] = a[(imm >> 2) & 0x3];
+//       ret[2] = b[(imm >> 4) & 0x03];  ret[3] = b[(imm >> 6) & 0x03];
+//       return ret;
+//   }
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx
+#define _mm_shuffle_ps_default(a, b, imm)                                  \
+    __extension__({                                                        \
+        float32x4_t ret;                                                   \
+        ret = vmovq_n_f32(                                                 \
+            vgetq_lane_f32(vreinterpretq_f32_m128(a), (imm) & (0x3)));     \
+        ret = vsetq_lane_f32(                                              \
+            vgetq_lane_f32(vreinterpretq_f32_m128(a), ((imm) >> 2) & 0x3), \
+            ret, 1);                                                       \
+        ret = vsetq_lane_f32(                                              \
+            vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 4) & 0x3), \
+            ret, 2);                                                       \
+        ret = vsetq_lane_f32(                                              \
+            vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 6) & 0x3), \
+            ret, 3);                                                       \
+        vreinterpretq_m128_f32(ret);                                       \
+    })
+
+// FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255)
+// int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_ps(a, b, imm)                                \
+    __extension__({                                              \
+        float32x4_t _input1 = vreinterpretq_f32_m128(a);         \
+        float32x4_t _input2 = vreinterpretq_f32_m128(b);         \
+        float32x4_t _shuf = __builtin_shufflevector(             \
+            _input1, _input2, (imm) & (0x3), ((imm) >> 2) & 0x3, \
+            (((imm) >> 4) & 0x3) + 4, (((imm) >> 6) & 0x3) + 4); \
+        vreinterpretq_m128_f32(_shuf);                           \
+    })
+#else  // generic
+#define _mm_shuffle_ps(a, b, imm)                          \
+    __extension__({                                        \
+        __m128 ret;                                        \
+        switch (imm) {                                     \
+        case _MM_SHUFFLE(1, 0, 3, 2):                      \
+            ret = _mm_shuffle_ps_1032((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(2, 3, 0, 1):                      \
+            ret = _mm_shuffle_ps_2301((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(0, 3, 2, 1):                      \
+            ret = _mm_shuffle_ps_0321((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(2, 1, 0, 3):                      \
+            ret = _mm_shuffle_ps_2103((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(1, 0, 1, 0):                      \
+            ret = _mm_movelh_ps((a), (b));                 \
+            break;                                         \
+        case _MM_SHUFFLE(1, 0, 0, 1):                      \
+            ret = _mm_shuffle_ps_1001((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(0, 1, 0, 1):                      \
+            ret = _mm_shuffle_ps_0101((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(3, 2, 1, 0):                      \
+            ret = _mm_shuffle_ps_3210((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(0, 0, 1, 1):                      \
+            ret = _mm_shuffle_ps_0011((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(0, 0, 2, 2):                      \
+            ret = _mm_shuffle_ps_0022((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(2, 2, 0, 0):                      \
+            ret = _mm_shuffle_ps_2200((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(3, 2, 0, 2):                      \
+            ret = _mm_shuffle_ps_3202((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(3, 2, 3, 2):                      \
+            ret = _mm_movehl_ps((b), (a));                 \
+            break;                                         \
+        case _MM_SHUFFLE(1, 1, 3, 3):                      \
+            ret = _mm_shuffle_ps_1133((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(2, 0, 1, 0):                      \
+            ret = _mm_shuffle_ps_2010((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(2, 0, 0, 1):                      \
+            ret = _mm_shuffle_ps_2001((a), (b));           \
+            break;                                         \
+        case _MM_SHUFFLE(2, 0, 3, 2):                      \
+            ret = _mm_shuffle_ps_2032((a), (b));           \
+            break;                                         \
+        default:                                           \
+            ret = _mm_shuffle_ps_default((a), (b), (imm)); \
+            break;                                         \
+        }                                                  \
+        ret;                                               \
+    })
+#endif
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of a and places it into the high end of the result.
+FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a)
+{
+    int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a));
+    int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+    return vreinterpretq_m128i_s32(vcombine_s32(a32, a10));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in low end
+// of result takes the higher two 32 bit values from a and swaps them and places
+// in high end of result.
+FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a)
+{
+    int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+    int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a)));
+    return vreinterpretq_m128i_s32(vcombine_s32(a01, a23));
+}
+
+// rotates the least significant 32 bits into the most signficant 32 bits, and
+// shifts the rest down
+FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a)
+{
+    return vreinterpretq_m128i_s32(
+        vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1));
+}
+
+// rotates the most significant 32 bits into the least signficant 32 bits, and
+// shifts the rest up
+FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a)
+{
+    return vreinterpretq_m128i_s32(
+        vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3));
+}
+
+// gets the lower 64 bits of a, and places it in the upper 64 bits
+// gets the lower 64 bits of a and places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a)
+{
+    int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+    return vreinterpretq_m128i_s32(vcombine_s32(a10, a10));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the
+// lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a)
+{
+    int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+    int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+    return vreinterpretq_m128i_s32(vcombine_s32(a01, a10));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the
+// upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and
+// places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a)
+{
+    int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+    return vreinterpretq_m128i_s32(vcombine_s32(a01, a01));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a)
+{
+    int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1);
+    int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0);
+    return vreinterpretq_m128i_s32(vcombine_s32(a11, a22));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a)
+{
+    int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0);
+    int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+    return vreinterpretq_m128i_s32(vcombine_s32(a22, a01));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a)
+{
+    int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a));
+    int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1);
+    return vreinterpretq_m128i_s32(vcombine_s32(a32, a33));
+}
+
+// Shuffle packed 8-bit integers in a according to shuffle control mask in the
+// corresponding 8-bit element of b, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8
+FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b)
+{
+    int8x16_t tbl = vreinterpretq_s8_m128i(a);   // input a
+    uint8x16_t idx = vreinterpretq_u8_m128i(b);  // input b
+    uint8x16_t idx_masked =
+        vandq_u8(idx, vdupq_n_u8(0x8F));  // avoid using meaningless bits
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked));
+#elif defined(__GNUC__)
+    int8x16_t ret;
+    // %e and %f represent the even and odd D registers
+    // respectively.
+    __asm__ __volatile__(
+        "vtbl.8  %e[ret], {%e[tbl], %f[tbl]}, %e[idx]\n"
+        "vtbl.8  %f[ret], {%e[tbl], %f[tbl]}, %f[idx]\n"
+        : [ret] "=&w"(ret)
+        : [tbl] "w"(tbl), [idx] "w"(idx_masked));
+    return vreinterpretq_m128i_s8(ret);
+#else
+    // use this line if testing on aarch64
+    int8x8x2_t a_split = {vget_low_s8(tbl), vget_high_s8(tbl)};
+    return vreinterpretq_m128i_s8(
+        vcombine_s8(vtbl2_s8(a_split, vget_low_u8(idx_masked)),
+                    vtbl2_s8(a_split, vget_high_u8(idx_masked))));
+#endif
+}
+
+// C equivalent:
+//   __m128i _mm_shuffle_epi32_default(__m128i a,
+//                                     __constrange(0, 255) int imm) {
+//       __m128i ret;
+//       ret[0] = a[imm        & 0x3];   ret[1] = a[(imm >> 2) & 0x3];
+//       ret[2] = a[(imm >> 4) & 0x03];  ret[3] = a[(imm >> 6) & 0x03];
+//       return ret;
+//   }
+#define _mm_shuffle_epi32_default(a, imm)                                   \
+    __extension__({                                                         \
+        int32x4_t ret;                                                      \
+        ret = vmovq_n_s32(                                                  \
+            vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) & (0x3)));     \
+        ret = vsetq_lane_s32(                                               \
+            vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \
+            ret, 1);                                                        \
+        ret = vsetq_lane_s32(                                               \
+            vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \
+            ret, 2);                                                        \
+        ret = vsetq_lane_s32(                                               \
+            vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \
+            ret, 3);                                                        \
+        vreinterpretq_m128i_s32(ret);                                       \
+    })
+
+// FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255)
+// int imm)
+#if defined(__aarch64__)
+#define _mm_shuffle_epi32_splat(a, imm)                          \
+    __extension__({                                              \
+        vreinterpretq_m128i_s32(                                 \
+            vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \
+    })
+#else
+#define _mm_shuffle_epi32_splat(a, imm)                                      \
+    __extension__({                                                          \
+        vreinterpretq_m128i_s32(                                             \
+            vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \
+    })
+#endif
+
+// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm.
+// https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx
+// FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a,
+//                                        __constrange(0,255) int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_epi32(a, imm)                              \
+    __extension__({                                            \
+        int32x4_t _input = vreinterpretq_s32_m128i(a);         \
+        int32x4_t _shuf = __builtin_shufflevector(             \
+            _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \
+            ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3);           \
+        vreinterpretq_m128i_s32(_shuf);                        \
+    })
+#else  // generic
+#define _mm_shuffle_epi32(a, imm)                        \
+    __extension__({                                      \
+        __m128i ret;                                     \
+        switch (imm) {                                   \
+        case _MM_SHUFFLE(1, 0, 3, 2):                    \
+            ret = _mm_shuffle_epi_1032((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(2, 3, 0, 1):                    \
+            ret = _mm_shuffle_epi_2301((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(0, 3, 2, 1):                    \
+            ret = _mm_shuffle_epi_0321((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(2, 1, 0, 3):                    \
+            ret = _mm_shuffle_epi_2103((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(1, 0, 1, 0):                    \
+            ret = _mm_shuffle_epi_1010((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(1, 0, 0, 1):                    \
+            ret = _mm_shuffle_epi_1001((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(0, 1, 0, 1):                    \
+            ret = _mm_shuffle_epi_0101((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(2, 2, 1, 1):                    \
+            ret = _mm_shuffle_epi_2211((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(0, 1, 2, 2):                    \
+            ret = _mm_shuffle_epi_0122((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(3, 3, 3, 2):                    \
+            ret = _mm_shuffle_epi_3332((a));             \
+            break;                                       \
+        case _MM_SHUFFLE(0, 0, 0, 0):                    \
+            ret = _mm_shuffle_epi32_splat((a), 0);       \
+            break;                                       \
+        case _MM_SHUFFLE(1, 1, 1, 1):                    \
+            ret = _mm_shuffle_epi32_splat((a), 1);       \
+            break;                                       \
+        case _MM_SHUFFLE(2, 2, 2, 2):                    \
+            ret = _mm_shuffle_epi32_splat((a), 2);       \
+            break;                                       \
+        case _MM_SHUFFLE(3, 3, 3, 3):                    \
+            ret = _mm_shuffle_epi32_splat((a), 3);       \
+            break;                                       \
+        default:                                         \
+            ret = _mm_shuffle_epi32_default((a), (imm)); \
+            break;                                       \
+        }                                                \
+        ret;                                             \
+    })
+#endif
+
+// Shuffles the lower 4 signed or unsigned 16-bit integers in a as specified
+// by imm.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/y41dkk37(v=vs.100)
+// FORCE_INLINE __m128i _mm_shufflelo_epi16_function(__m128i a,
+//                                                   __constrange(0,255) int
+//                                                   imm)
+#define _mm_shufflelo_epi16_function(a, imm)                                  \
+    __extension__({                                                           \
+        int16x8_t ret = vreinterpretq_s16_m128i(a);                           \
+        int16x4_t lowBits = vget_low_s16(ret);                                \
+        ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) & (0x3)), ret, 0);  \
+        ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \
+                             1);                                              \
+        ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \
+                             2);                                              \
+        ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \
+                             3);                                              \
+        vreinterpretq_m128i_s16(ret);                                         \
+    })
+
+// FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a,
+//                                          __constrange(0,255) int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shufflelo_epi16(a, imm)                                  \
+    __extension__({                                                  \
+        int16x8_t _input = vreinterpretq_s16_m128i(a);               \
+        int16x8_t _shuf = __builtin_shufflevector(                   \
+            _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3),   \
+            (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \
+        vreinterpretq_m128i_s16(_shuf);                              \
+    })
+#else  // generic
+#define _mm_shufflelo_epi16(a, imm) _mm_shufflelo_epi16_function((a), (imm))
+#endif
+
+// Shuffles the upper 4 signed or unsigned 16-bit integers in a as specified
+// by imm.
+// https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a,
+//                                                   __constrange(0,255) int
+//                                                   imm)
+#define _mm_shufflehi_epi16_function(a, imm)                                   \
+    __extension__({                                                            \
+        int16x8_t ret = vreinterpretq_s16_m128i(a);                            \
+        int16x4_t highBits = vget_high_s16(ret);                               \
+        ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) & (0x3)), ret, 4);  \
+        ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \
+                             5);                                               \
+        ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \
+                             6);                                               \
+        ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \
+                             7);                                               \
+        vreinterpretq_m128i_s16(ret);                                          \
+    })
+
+// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a,
+//                                          __constrange(0,255) int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shufflehi_epi16(a, imm)                             \
+    __extension__({                                             \
+        int16x8_t _input = vreinterpretq_s16_m128i(a);          \
+        int16x8_t _shuf = __builtin_shufflevector(              \
+            _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4,    \
+            (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \
+            (((imm) >> 6) & 0x3) + 4);                          \
+        vreinterpretq_m128i_s16(_shuf);                         \
+    })
+#else  // generic
+#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm))
+#endif
+
+// Shuffle double-precision (64-bit) floating-point elements using the control
+// in imm8, and store the results in dst.
+//
+//   dst[63:0] := (imm8[0] == 0) ? a[63:0] : a[127:64]
+//   dst[127:64] := (imm8[1] == 0) ? b[63:0] : b[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_pd(a, b, imm8)                                          \
+    vreinterpretq_m128d_s64(__builtin_shufflevector(                        \
+        vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), imm8 & 0x1, \
+        ((imm8 & 0x2) >> 1) + 2))
+#else
+#define _mm_shuffle_pd(a, b, imm8)                                     \
+    _mm_castsi128_pd(_mm_set_epi64x(                                   \
+        vgetq_lane_s64(vreinterpretq_s64_m128d(b), (imm8 & 0x2) >> 1), \
+        vgetq_lane_s64(vreinterpretq_s64_m128d(a), imm8 & 0x1)))
+#endif
+
+// Blend packed 16-bit integers from a and b using control mask imm8, and store
+// the results in dst.
+//
+//   FOR j := 0 to 7
+//       i := j*16
+//       IF imm8[j]
+//           dst[i+15:i] := b[i+15:i]
+//       ELSE
+//           dst[i+15:i] := a[i+15:i]
+//       FI
+//   ENDFOR
+// FORCE_INLINE __m128i _mm_blend_epi16(__m128i a, __m128i b,
+//                                      __constrange(0,255) int imm)
+#define _mm_blend_epi16(a, b, imm)                                        \
+    __extension__({                                                       \
+        const uint16_t _mask[8] = {((imm) & (1 << 0)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 1)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 2)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 3)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 4)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 5)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 6)) ? 0xFFFF : 0x0000,  \
+                                   ((imm) & (1 << 7)) ? 0xFFFF : 0x0000}; \
+        uint16x8_t _mask_vec = vld1q_u16(_mask);                          \
+        uint16x8_t _a = vreinterpretq_u16_m128i(a);                       \
+        uint16x8_t _b = vreinterpretq_u16_m128i(b);                       \
+        vreinterpretq_m128i_u16(vbslq_u16(_mask_vec, _b, _a));            \
+    })
+
+// Blend packed 8-bit integers from a and b using mask, and store the results in
+// dst.
+//
+//   FOR j := 0 to 15
+//       i := j*8
+//       IF mask[i+7]
+//           dst[i+7:i] := b[i+7:i]
+//       ELSE
+//           dst[i+7:i] := a[i+7:i]
+//       FI
+//   ENDFOR
+FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask)
+{
+    // Use a signed shift right to create a mask with the sign bit
+    uint8x16_t mask =
+        vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_m128i(_mask), 7));
+    uint8x16_t a = vreinterpretq_u8_m128i(_a);
+    uint8x16_t b = vreinterpretq_u8_m128i(_b);
+    return vreinterpretq_m128i_u8(vbslq_u8(mask, b, a));
+}
+
+/* Shifts */
+
+
+// Shift packed 16-bit integers in a right by imm while shifting in sign
+// bits, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16
+FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm)
+{
+    const int count = (imm & ~15) ? 15 : imm;
+    return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count));
+}
+
+// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while
+// shifting in zeros.
+//
+//   r0 := a0 << count
+//   r1 := a1 << count
+//   ...
+//   r7 := a7 << count
+//
+// https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx
+#define _mm_slli_epi16(a, imm)                                   \
+    __extension__({                                              \
+        __m128i ret;                                             \
+        if (unlikely((imm)) <= 0) {                              \
+            ret = a;                                             \
+        }                                                        \
+        if (unlikely((imm) > 15)) {                              \
+            ret = _mm_setzero_si128();                           \
+        } else {                                                 \
+            ret = vreinterpretq_m128i_s16(                       \
+                vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \
+        }                                                        \
+        ret;                                                     \
+    })
+
+// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while
+// shifting in zeros. :
+// https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx
+// FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm)
+FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm)
+{
+    if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */
+        return a;
+    if (unlikely(imm > 31))
+        return _mm_setzero_si128();
+    return vreinterpretq_m128i_s32(
+        vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(imm)));
+}
+
+// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and
+// store the results in dst.
+FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm)
+{
+    if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */
+        return a;
+    if (unlikely(imm > 63))
+        return _mm_setzero_si128();
+    return vreinterpretq_m128i_s64(
+        vshlq_s64(vreinterpretq_s64_m128i(a), vdupq_n_s64(imm)));
+}
+
+// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+//
+//   FOR j := 0 to 7
+//     i := j*16
+//     IF imm8[7:0] > 15
+//       dst[i+15:i] := 0
+//     ELSE
+//       dst[i+15:i] := ZeroExtend16(a[i+15:i] >> imm8[7:0])
+//     FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16
+#define _mm_srli_epi16(a, imm)                                             \
+    __extension__({                                                        \
+        __m128i ret;                                                       \
+        if (unlikely(imm) == 0) {                                          \
+            ret = a;                                                       \
+        }                                                                  \
+        if (likely(0 < (imm) && (imm) < 16)) {                             \
+            ret = vreinterpretq_m128i_u16(                                 \
+                vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-imm))); \
+        } else {                                                           \
+            ret = _mm_setzero_si128();                                     \
+        }                                                                  \
+        ret;                                                               \
+    })
+
+// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+//
+//   FOR j := 0 to 3
+//     i := j*32
+//     IF imm8[7:0] > 31
+//       dst[i+31:i] := 0
+//     ELSE
+//       dst[i+31:i] := ZeroExtend32(a[i+31:i] >> imm8[7:0])
+//     FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32
+// FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_srli_epi32(a, imm)                                             \
+    __extension__({                                                        \
+        __m128i ret;                                                       \
+        if (unlikely((imm) == 0)) {                                        \
+            ret = a;                                                       \
+        }                                                                  \
+        if (likely(0 < (imm) && (imm) < 32)) {                             \
+            ret = vreinterpretq_m128i_u32(                                 \
+                vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-imm))); \
+        } else {                                                           \
+            ret = _mm_setzero_si128();                                     \
+        }                                                                  \
+        ret;                                                               \
+    })
+
+// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+//
+//   FOR j := 0 to 1
+//     i := j*64
+//     IF imm8[7:0] > 63
+//       dst[i+63:i] := 0
+//     ELSE
+//       dst[i+63:i] := ZeroExtend64(a[i+63:i] >> imm8[7:0])
+//     FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64
+#define _mm_srli_epi64(a, imm)                                             \
+    __extension__({                                                        \
+        __m128i ret;                                                       \
+        if (unlikely((imm) == 0)) {                                        \
+            ret = a;                                                       \
+        }                                                                  \
+        if (likely(0 < (imm) && (imm) < 64)) {                             \
+            ret = vreinterpretq_m128i_u64(                                 \
+                vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-imm))); \
+        } else {                                                           \
+            ret = _mm_setzero_si128();                                     \
+        }                                                                  \
+        ret;                                                               \
+    })
+
+// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits,
+// and store the results in dst.
+//
+//   FOR j := 0 to 3
+//     i := j*32
+//     IF imm8[7:0] > 31
+//       dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0)
+//     ELSE
+//       dst[i+31:i] := SignExtend32(a[i+31:i] >> imm8[7:0])
+//     FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32
+// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_srai_epi32(a, imm)                                             \
+    __extension__({                                                        \
+        __m128i ret;                                                       \
+        if (unlikely((imm) == 0)) {                                        \
+            ret = a;                                                       \
+        }                                                                  \
+        if (likely(0 < (imm) && (imm) < 32)) {                             \
+            ret = vreinterpretq_m128i_s32(                                 \
+                vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \
+        } else {                                                           \
+            ret = vreinterpretq_m128i_s32(                                 \
+                vshrq_n_s32(vreinterpretq_s32_m128i(a), 31));              \
+        }                                                                  \
+        ret;                                                               \
+    })
+
+// Shifts the 128 - bit value in a right by imm bytes while shifting in
+// zeros.imm must be an immediate.
+//
+//   r := srl(a, imm*8)
+//
+// https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx
+// FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm)
+#define _mm_srli_si128(a, imm)                                              \
+    __extension__({                                                         \
+        __m128i ret;                                                        \
+        if (unlikely((imm) <= 0)) {                                         \
+            ret = a;                                                        \
+        }                                                                   \
+        if (unlikely((imm) > 15)) {                                         \
+            ret = _mm_setzero_si128();                                      \
+        } else {                                                            \
+            ret = vreinterpretq_m128i_s8(                                   \
+                vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \
+        }                                                                   \
+        ret;                                                                \
+    })
+
+// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm
+// must be an immediate.
+//
+//   r := a << (imm * 8)
+//
+// https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm)
+#define _mm_slli_si128(a, imm)                                          \
+    __extension__({                                                     \
+        __m128i ret;                                                    \
+        if (unlikely((imm) <= 0)) {                                     \
+            ret = a;                                                    \
+        }                                                               \
+        if (unlikely((imm) > 15)) {                                     \
+            ret = _mm_setzero_si128();                                  \
+        } else {                                                        \
+            ret = vreinterpretq_m128i_s8(vextq_s8(                      \
+                vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \
+        }                                                               \
+        ret;                                                            \
+    })
+
+// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while
+// shifting in zeros.
+//
+//   r0 := a0 << count
+//   r1 := a1 << count
+//   ...
+//   r7 := a7 << count
+//
+// https://msdn.microsoft.com/en-us/library/c79w388h(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count)
+{
+    uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+    if (unlikely(c > 15))
+        return _mm_setzero_si128();
+
+    int16x8_t vc = vdupq_n_s16((int16_t) c);
+    return vreinterpretq_m128i_s16(vshlq_s16(vreinterpretq_s16_m128i(a), vc));
+}
+
+// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+// r2 := a2 << count
+// r3 := a3 << count
+//
+// https://msdn.microsoft.com/en-us/library/6fe5a6s9(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count)
+{
+    uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+    if (unlikely(c > 31))
+        return _mm_setzero_si128();
+
+    int32x4_t vc = vdupq_n_s32((int32_t) c);
+    return vreinterpretq_m128i_s32(vshlq_s32(vreinterpretq_s32_m128i(a), vc));
+}
+
+// Shifts the 2 signed or unsigned 64-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+//
+// https://msdn.microsoft.com/en-us/library/6ta9dffd(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count)
+{
+    uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+    if (unlikely(c > 63))
+        return _mm_setzero_si128();
+
+    int64x2_t vc = vdupq_n_s64((int64_t) c);
+    return vreinterpretq_m128i_s64(vshlq_s64(vreinterpretq_s64_m128i(a), vc));
+}
+
+// Shifts the 8 signed or unsigned 16-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+// ...
+// r7 := srl(a7, count)
+//
+// https://msdn.microsoft.com/en-us/library/wd5ax830(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count)
+{
+    uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+    if (unlikely(c > 15))
+        return _mm_setzero_si128();
+
+    int16x8_t vc = vdupq_n_s16(-(int16_t) c);
+    return vreinterpretq_m128i_u16(vshlq_u16(vreinterpretq_u16_m128i(a), vc));
+}
+
+// Shifts the 4 signed or unsigned 32-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+// r2 := srl(a2, count)
+// r3 := srl(a3, count)
+//
+// https://msdn.microsoft.com/en-us/library/a9cbttf4(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count)
+{
+    uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+    if (unlikely(c > 31))
+        return _mm_setzero_si128();
+
+    int32x4_t vc = vdupq_n_s32(-(int32_t) c);
+    return vreinterpretq_m128i_u32(vshlq_u32(vreinterpretq_u32_m128i(a), vc));
+}
+
+// Shifts the 2 signed or unsigned 64-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+//
+// https://msdn.microsoft.com/en-us/library/yf6cf9k8(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count)
+{
+    uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+    if (unlikely(c > 63))
+        return _mm_setzero_si128();
+
+    int64x2_t vc = vdupq_n_s64(-(int64_t) c);
+    return vreinterpretq_m128i_u64(vshlq_u64(vreinterpretq_u64_m128i(a), vc));
+}
+
+// NEON does not provide a version of this function.
+// Creates a 16-bit mask from the most significant bits of the 16 signed or
+// unsigned 8-bit integers in a and zero extends the upper bits.
+// https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_epi8(__m128i a)
+{
+    // Use increasingly wide shifts+adds to collect the sign bits
+    // together.
+    // Since the widening shifts would be rather confusing to follow in little
+    // endian, everything will be illustrated in big endian order instead. This
+    // has a different result - the bits would actually be reversed on a big
+    // endian machine.
+
+    // Starting input (only half the elements are shown):
+    // 89 ff 1d c0 00 10 99 33
+    uint8x16_t input = vreinterpretq_u8_m128i(a);
+
+    // Shift out everything but the sign bits with an unsigned shift right.
+    //
+    // Bytes of the vector::
+    // 89 ff 1d c0 00 10 99 33
+    // \  \  \  \  \  \  \  \    high_bits = (uint16x4_t)(input >> 7)
+    //  |  |  |  |  |  |  |  |
+    // 01 01 00 01 00 00 01 00
+    //
+    // Bits of first important lane(s):
+    // 10001001 (89)
+    // \______
+    //        |
+    // 00000001 (01)
+    uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(input, 7));
+
+    // Merge the even lanes together with a 16-bit unsigned shift right + add.
+    // 'xx' represents garbage data which will be ignored in the final result.
+    // In the important bytes, the add functions like a binary OR.
+    //
+    // 01 01 00 01 00 00 01 00
+    //  \_ |  \_ |  \_ |  \_ |   paired16 = (uint32x4_t)(input + (input >> 7))
+    //    \|    \|    \|    \|
+    // xx 03 xx 01 xx 00 xx 02
+    //
+    // 00000001 00000001 (01 01)
+    //        \_______ |
+    //                \|
+    // xxxxxxxx xxxxxx11 (xx 03)
+    uint32x4_t paired16 =
+        vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7));
+
+    // Repeat with a wider 32-bit shift + add.
+    // xx 03 xx 01 xx 00 xx 02
+    //     \____ |     \____ |  paired32 = (uint64x1_t)(paired16 + (paired16 >>
+    //     14))
+    //          \|          \|
+    // xx xx xx 0d xx xx xx 02
+    //
+    // 00000011 00000001 (03 01)
+    //        \\_____ ||
+    //         '----.\||
+    // xxxxxxxx xxxx1101 (xx 0d)
+    uint64x2_t paired32 =
+        vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14));
+
+    // Last, an even wider 64-bit shift + add to get our result in the low 8 bit
+    // lanes. xx xx xx 0d xx xx xx 02
+    //            \_________ |   paired64 = (uint8x8_t)(paired32 + (paired32 >>
+    //            28))
+    //                      \|
+    // xx xx xx xx xx xx xx d2
+    //
+    // 00001101 00000010 (0d 02)
+    //     \   \___ |  |
+    //      '---.  \|  |
+    // xxxxxxxx 11010010 (xx d2)
+    uint8x16_t paired64 =
+        vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28));
+
+    // Extract the low 8 bits from each 64-bit lane with 2 8-bit extracts.
+    // xx xx xx xx xx xx xx d2
+    //                      ||  return paired64[0]
+    //                      d2
+    // Note: Little endian would return the correct value 4b (01001011) instead.
+    return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8);
+}
+
+// Copy the lower 64-bit integer in a to dst.
+//
+//   dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi64_pi64
+FORCE_INLINE __m64 _mm_movepi64_pi64(__m128i a)
+{
+    return vreinterpret_m64_s64(vget_low_s64(vreinterpretq_s64_m128i(a)));
+}
+
+// Copy the 64-bit integer a to the lower element of dst, and zero the upper
+// element.
+//
+//   dst[63:0] := a[63:0]
+//   dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movpi64_epi64
+FORCE_INLINE __m128i _mm_movpi64_epi64(__m64 a)
+{
+    return vreinterpretq_m128i_s64(
+        vcombine_s64(vreinterpret_s64_m64(a), vdup_n_s64(0)));
+}
+
+// NEON does not provide this method
+// Creates a 4-bit mask from the most significant bits of the four
+// single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_ps(__m128 a)
+{
+    uint32x4_t input = vreinterpretq_u32_m128(a);
+#if defined(__aarch64__)
+    static const int32x4_t shift = {0, 1, 2, 3};
+    uint32x4_t tmp = vshrq_n_u32(input, 31);
+    return vaddvq_u32(vshlq_u32(tmp, shift));
+#else
+    // Uses the exact same method as _mm_movemask_epi8, see that for details.
+    // Shift out everything but the sign bits with a 32-bit unsigned shift
+    // right.
+    uint64x2_t high_bits = vreinterpretq_u64_u32(vshrq_n_u32(input, 31));
+    // Merge the two pairs together with a 64-bit unsigned shift right + add.
+    uint8x16_t paired =
+        vreinterpretq_u8_u64(vsraq_n_u64(high_bits, high_bits, 31));
+    // Extract the result.
+    return vgetq_lane_u8(paired, 0) | (vgetq_lane_u8(paired, 8) << 2);
+#endif
+}
+
+// Compute the bitwise NOT of a and then AND with a 128-bit vector containing
+// all 1's, and return 1 if the result is zero, otherwise return 0.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones
+FORCE_INLINE int _mm_test_all_ones(__m128i a)
+{
+    return (uint64_t)(vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) ==
+           ~(uint64_t) 0;
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and
+// mask, and return 1 if the result is zero, otherwise return 0.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros
+FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask)
+{
+    int64x2_t a_and_mask =
+        vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask));
+    return (vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)) ? 0
+                                                                           : 1;
+}
+
+/* Math operations */
+
+// Subtracts the four single-precision, floating-point values of a and b.
+//
+//   r0 := a0 - b0
+//   r1 := a1 - b1
+//   r2 := a2 - b2
+//   r3 := a3 - b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_f32(
+        vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Subtract the lower single-precision (32-bit) floating-point element in b from
+// the lower single-precision (32-bit) floating-point element in a, store the
+// result in the lower element of dst, and copy the upper 3 packed elements from
+// a to the upper elements of dst.
+//
+//   dst[31:0] := a[31:0] - b[31:0]
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss
+FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_sub_ps(a, b));
+}
+
+// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a,
+// and store the results in dst.
+//    r0 := a0 - b0
+//    r1 := a1 - b1
+FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s64(
+        vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+}
+
+// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or
+// unsigned 32-bit integers of a.
+//
+//   r0 := a0 - b0
+//   r1 := a1 - b1
+//   r2 := a2 - b2
+//   r3 := a3 - b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vsubq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and
+// store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi16
+FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and
+// store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi8
+FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Subtract 64-bit integer b from 64-bit integer a, and store the result in dst.
+//
+//   dst[63:0] := a[63:0] - b[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64
+FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_s64(
+        vsub_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b)));
+}
+
+// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit
+// integers of a and saturates..
+// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit
+// integers of a and saturates.
+//
+//   r0 := UnsignedSaturate(a0 - b0)
+//   r1 := UnsignedSaturate(a1 - b1)
+//   ...
+//   r15 := UnsignedSaturate(a15 - b15)
+//
+// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Subtracts the 16 signed 8-bit integers of b from the 16 signed 8-bit integers
+// of a and saturates.
+//
+//   r0 := SignedSaturate(a0 - b0)
+//   r1 := SignedSaturate(a1 - b1)
+//   ...
+//   r15 := SignedSaturate(a15 - b15)
+//
+// https://technet.microsoft.com/en-us/subscriptions/by7kzks1(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vqsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers
+// of a and saturates.
+//
+//   r0 := SignedSaturate(a0 - b0)
+//   r1 := SignedSaturate(a1 - b1)
+//   ...
+//   r7 := SignedSaturate(a7 - b7)
+//
+// https://technet.microsoft.com/en-us/subscriptions/3247z5b8(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Subtract packed double-precision (64-bit) floating-point elements in b from
+// packed double-precision (64-bit) floating-point elements in a, and store the
+// results in dst.
+//
+//   FOR j := 0 to 1
+//     i := j*64
+//     dst[i+63:i] := a[i+63:i] - b[i+63:i]
+//   ENDFOR
+//
+//  https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sub_pd
+FORCE_INLINE __m128d _mm_sub_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vsubq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    double *da = (double *) &a;
+    double *db = (double *) &b;
+    double c[2];
+    c[0] = da[0] - db[0];
+    c[1] = da[1] - db[1];
+    return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Subtract the lower double-precision (64-bit) floating-point element in b from
+// the lower double-precision (64-bit) floating-point element in a, store the
+// result in the lower element of dst, and copy the upper element from a to the
+// upper element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_sd
+FORCE_INLINE __m128d _mm_sub_sd(__m128d a, __m128d b)
+{
+    return _mm_move_sd(a, _mm_sub_pd(a, b));
+}
+
+// Add packed unsigned 16-bit integers in a and b using saturation, and store
+// the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epu16
+FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Negate packed 8-bit integers in a when the corresponding signed
+// 8-bit integer in b is negative, and store the results in dst.
+// Element in dst are zeroed out when the corresponding element
+// in b is zero.
+//
+//   for i in 0..15
+//     if b[i] < 0
+//       r[i] := -a[i]
+//     else if b[i] == 0
+//       r[i] := 0
+//     else
+//       r[i] := a[i]
+//     fi
+//   done
+FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b)
+{
+    int8x16_t a = vreinterpretq_s8_m128i(_a);
+    int8x16_t b = vreinterpretq_s8_m128i(_b);
+
+    // signed shift right: faster than vclt
+    // (b < 0) ? 0xFF : 0
+    uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7));
+
+    // (b == 0) ? 0xFF : 0
+#if defined(__aarch64__)
+    int8x16_t zeroMask = vreinterpretq_s8_u8(vceqzq_s8(b));
+#else
+    int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0)));
+#endif
+
+    // bitwise select either a or nagative 'a' (vnegq_s8(a) return nagative 'a')
+    // based on ltMask
+    int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a);
+    // res = masked & (~zeroMask)
+    int8x16_t res = vbicq_s8(masked, zeroMask);
+
+    return vreinterpretq_m128i_s8(res);
+}
+
+// Negate packed 16-bit integers in a when the corresponding signed
+// 16-bit integer in b is negative, and store the results in dst.
+// Element in dst are zeroed out when the corresponding element
+// in b is zero.
+//
+//   for i in 0..7
+//     if b[i] < 0
+//       r[i] := -a[i]
+//     else if b[i] == 0
+//       r[i] := 0
+//     else
+//       r[i] := a[i]
+//     fi
+//   done
+FORCE_INLINE __m128i _mm_sign_epi16(__m128i _a, __m128i _b)
+{
+    int16x8_t a = vreinterpretq_s16_m128i(_a);
+    int16x8_t b = vreinterpretq_s16_m128i(_b);
+
+    // signed shift right: faster than vclt
+    // (b < 0) ? 0xFFFF : 0
+    uint16x8_t ltMask = vreinterpretq_u16_s16(vshrq_n_s16(b, 15));
+    // (b == 0) ? 0xFFFF : 0
+#if defined(__aarch64__)
+    int16x8_t zeroMask = vreinterpretq_s16_u16(vceqzq_s16(b));
+#else
+    int16x8_t zeroMask = vreinterpretq_s16_u16(vceqq_s16(b, vdupq_n_s16(0)));
+#endif
+
+    // bitwise select either a or negative 'a' (vnegq_s16(a) equals to negative
+    // 'a') based on ltMask
+    int16x8_t masked = vbslq_s16(ltMask, vnegq_s16(a), a);
+    // res = masked & (~zeroMask)
+    int16x8_t res = vbicq_s16(masked, zeroMask);
+    return vreinterpretq_m128i_s16(res);
+}
+
+// Negate packed 32-bit integers in a when the corresponding signed
+// 32-bit integer in b is negative, and store the results in dst.
+// Element in dst are zeroed out when the corresponding element
+// in b is zero.
+//
+//   for i in 0..3
+//     if b[i] < 0
+//       r[i] := -a[i]
+//     else if b[i] == 0
+//       r[i] := 0
+//     else
+//       r[i] := a[i]
+//     fi
+//   done
+FORCE_INLINE __m128i _mm_sign_epi32(__m128i _a, __m128i _b)
+{
+    int32x4_t a = vreinterpretq_s32_m128i(_a);
+    int32x4_t b = vreinterpretq_s32_m128i(_b);
+
+    // signed shift right: faster than vclt
+    // (b < 0) ? 0xFFFFFFFF : 0
+    uint32x4_t ltMask = vreinterpretq_u32_s32(vshrq_n_s32(b, 31));
+
+    // (b == 0) ? 0xFFFFFFFF : 0
+#if defined(__aarch64__)
+    int32x4_t zeroMask = vreinterpretq_s32_u32(vceqzq_s32(b));
+#else
+    int32x4_t zeroMask = vreinterpretq_s32_u32(vceqq_s32(b, vdupq_n_s32(0)));
+#endif
+
+    // bitwise select either a or negative 'a' (vnegq_s32(a) equals to negative
+    // 'a') based on ltMask
+    int32x4_t masked = vbslq_s32(ltMask, vnegq_s32(a), a);
+    // res = masked & (~zeroMask)
+    int32x4_t res = vbicq_s32(masked, zeroMask);
+    return vreinterpretq_m128i_s32(res);
+}
+
+// Negate packed 16-bit integers in a when the corresponding signed 16-bit
+// integer in b is negative, and store the results in dst. Element in dst are
+// zeroed out when the corresponding element in b is zero.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      IF b[i+15:i] < 0
+//        dst[i+15:i] := -(a[i+15:i])
+//      ELSE IF b[i+15:i] == 0
+//        dst[i+15:i] := 0
+//      ELSE
+//        dst[i+15:i] := a[i+15:i]
+//      FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi16
+FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b)
+{
+    int16x4_t a = vreinterpret_s16_m64(_a);
+    int16x4_t b = vreinterpret_s16_m64(_b);
+
+    // signed shift right: faster than vclt
+    // (b < 0) ? 0xFFFF : 0
+    uint16x4_t ltMask = vreinterpret_u16_s16(vshr_n_s16(b, 15));
+
+    // (b == 0) ? 0xFFFF : 0
+#if defined(__aarch64__)
+    int16x4_t zeroMask = vreinterpret_s16_u16(vceqz_s16(b));
+#else
+    int16x4_t zeroMask = vreinterpret_s16_u16(vceq_s16(b, vdup_n_s16(0)));
+#endif
+
+    // bitwise select either a or nagative 'a' (vneg_s16(a) return nagative 'a')
+    // based on ltMask
+    int16x4_t masked = vbsl_s16(ltMask, vneg_s16(a), a);
+    // res = masked & (~zeroMask)
+    int16x4_t res = vbic_s16(masked, zeroMask);
+
+    return vreinterpret_m64_s16(res);
+}
+
+// Negate packed 32-bit integers in a when the corresponding signed 32-bit
+// integer in b is negative, and store the results in dst. Element in dst are
+// zeroed out when the corresponding element in b is zero.
+//
+//   FOR j := 0 to 1
+//      i := j*32
+//      IF b[i+31:i] < 0
+//        dst[i+31:i] := -(a[i+31:i])
+//      ELSE IF b[i+31:i] == 0
+//        dst[i+31:i] := 0
+//      ELSE
+//        dst[i+31:i] := a[i+31:i]
+//      FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi32
+FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b)
+{
+    int32x2_t a = vreinterpret_s32_m64(_a);
+    int32x2_t b = vreinterpret_s32_m64(_b);
+
+    // signed shift right: faster than vclt
+    // (b < 0) ? 0xFFFFFFFF : 0
+    uint32x2_t ltMask = vreinterpret_u32_s32(vshr_n_s32(b, 31));
+
+    // (b == 0) ? 0xFFFFFFFF : 0
+#if defined(__aarch64__)
+    int32x2_t zeroMask = vreinterpret_s32_u32(vceqz_s32(b));
+#else
+    int32x2_t zeroMask = vreinterpret_s32_u32(vceq_s32(b, vdup_n_s32(0)));
+#endif
+
+    // bitwise select either a or nagative 'a' (vneg_s32(a) return nagative 'a')
+    // based on ltMask
+    int32x2_t masked = vbsl_s32(ltMask, vneg_s32(a), a);
+    // res = masked & (~zeroMask)
+    int32x2_t res = vbic_s32(masked, zeroMask);
+
+    return vreinterpret_m64_s32(res);
+}
+
+// Negate packed 8-bit integers in a when the corresponding signed 8-bit integer
+// in b is negative, and store the results in dst. Element in dst are zeroed out
+// when the corresponding element in b is zero.
+//
+//   FOR j := 0 to 7
+//      i := j*8
+//      IF b[i+7:i] < 0
+//        dst[i+7:i] := -(a[i+7:i])
+//      ELSE IF b[i+7:i] == 0
+//        dst[i+7:i] := 0
+//      ELSE
+//        dst[i+7:i] := a[i+7:i]
+//      FI
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi8
+FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b)
+{
+    int8x8_t a = vreinterpret_s8_m64(_a);
+    int8x8_t b = vreinterpret_s8_m64(_b);
+
+    // signed shift right: faster than vclt
+    // (b < 0) ? 0xFF : 0
+    uint8x8_t ltMask = vreinterpret_u8_s8(vshr_n_s8(b, 7));
+
+    // (b == 0) ? 0xFF : 0
+#if defined(__aarch64__)
+    int8x8_t zeroMask = vreinterpret_s8_u8(vceqz_s8(b));
+#else
+    int8x8_t zeroMask = vreinterpret_s8_u8(vceq_s8(b, vdup_n_s8(0)));
+#endif
+
+    // bitwise select either a or nagative 'a' (vneg_s8(a) return nagative 'a')
+    // based on ltMask
+    int8x8_t masked = vbsl_s8(ltMask, vneg_s8(a), a);
+    // res = masked & (~zeroMask)
+    int8x8_t res = vbic_s8(masked, zeroMask);
+
+    return vreinterpret_m64_s8(res);
+}
+
+// Average packed unsigned 16-bit integers in a and b, and store the results in
+// dst.
+//
+//   FOR j := 0 to 3
+//     i := j*16
+//     dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16
+FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_u16(
+        vrhadd_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)));
+}
+
+// Average packed unsigned 8-bit integers in a and b, and store the results in
+// dst.
+//
+//   FOR j := 0 to 7
+//     i := j*8
+//     dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8
+FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_u8(
+        vrhadd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+}
+
+// Average packed unsigned 8-bit integers in a and b, and store the results in
+// dst.
+//
+//   FOR j := 0 to 7
+//     i := j*8
+//     dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb
+#define _m_pavgb(a, b) _mm_avg_pu8(a, b)
+
+// Average packed unsigned 16-bit integers in a and b, and store the results in
+// dst.
+//
+//   FOR j := 0 to 3
+//     i := j*16
+//     dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw
+#define _m_pavgw(a, b) _mm_avg_pu16(a, b)
+
+// Extract a 16-bit integer from a, selected with imm8, and store the result in
+// the lower element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pextrw
+#define _m_pextrw(a, imm) _mm_extract_pi16(a, imm)
+
+// Copy a to dst, and insert the 16-bit integer i into dst at the location
+// specified by imm8.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_pinsrw
+#define _m_pinsrw(a, i, imm) _mm_insert_pi16(a, i, imm)
+
+// Compare packed signed 16-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxsw
+#define _m_pmaxsw(a, b) _mm_max_pi16(a, b)
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxub
+#define _m_pmaxub(a, b) _mm_max_pu8(a, b)
+
+// Compare packed signed 16-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminsw
+#define _m_pminsw(a, b) _mm_min_pi16(a, b)
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminub
+#define _m_pminub(a, b) _mm_min_pu8(a, b)
+
+// Computes the average of the 16 unsigned 8-bit integers in a and the 16
+// unsigned 8-bit integers in b and rounds.
+//
+//   r0 := (a0 + b0) / 2
+//   r1 := (a1 + b1) / 2
+//   ...
+//   r15 := (a15 + b15) / 2
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/8zwh554a(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vrhaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the average of the 8 unsigned 16-bit integers in a and the 8
+// unsigned 16-bit integers in b and rounds.
+//
+//   r0 := (a0 + b0) / 2
+//   r1 := (a1 + b1) / 2
+//   ...
+//   r7 := (a7 + b7) / 2
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/y13ca3c8(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_avg_epu16(__m128i a, __m128i b)
+{
+    return (__m128i) vrhaddq_u16(vreinterpretq_u16_m128i(a),
+                                 vreinterpretq_u16_m128i(b));
+}
+
+// Adds the four single-precision, floating-point values of a and b.
+//
+//   r0 := a0 + b0
+//   r1 := a1 + b1
+//   r2 := a2 + b2
+//   r3 := a3 + b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_f32(
+        vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Add packed double-precision (64-bit) floating-point elements in a and b, and
+// store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd
+FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    double *da = (double *) &a;
+    double *db = (double *) &b;
+    double c[2];
+    c[0] = da[0] + db[0];
+    c[1] = da[1] + db[1];
+    return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Add the lower double-precision (64-bit) floating-point element in a and b,
+// store the result in the lower element of dst, and copy the upper element from
+// a to the upper element of dst.
+//
+//   dst[63:0] := a[63:0] + b[63:0]
+//   dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_sd
+FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return _mm_move_sd(a, _mm_add_pd(a, b));
+#else
+    double *da = (double *) &a;
+    double *db = (double *) &b;
+    double c[2];
+    c[0] = da[0] + db[0];
+    c[1] = da[1];
+    return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Add 64-bit integers a and b, and store the result in dst.
+//
+//   dst[63:0] := a[63:0] + b[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64
+FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_s64(
+        vadd_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b)));
+}
+
+// adds the scalar single-precision floating point values of a and b.
+// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b)
+{
+    float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0);
+    float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0);
+    // the upper values in the result must be the remnants of <a>.
+    return vreinterpretq_m128_f32(vaddq_f32(a, value));
+}
+
+// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or
+// unsigned 32-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s64(
+        vaddq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+}
+
+// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or
+// unsigned 32-bit integers in b.
+//
+//   r0 := a0 + b0
+//   r1 := a1 + b1
+//   r2 := a2 + b2
+//   r3 := a3 + b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or
+// unsigned 16-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or
+// unsigned 8-bit integers in b.
+// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90)
+FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b
+// and saturates.
+//
+//   r0 := SignedSaturate(a0 + b0)
+//   r1 := SignedSaturate(a1 + b1)
+//   ...
+//   r7 := SignedSaturate(a7 + b7)
+//
+// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Add packed signed 8-bit integers in a and b using saturation, and store the
+// results in dst.
+//
+//   FOR j := 0 to 15
+//     i := j*8
+//     dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] )
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8
+FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vqaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in
+// b and saturates..
+// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or
+// unsigned 16-bit integers from b.
+//
+//   r0 := (a0 * b0)[15:0]
+//   r1 := (a1 * b1)[15:0]
+//   ...
+//   r7 := (a7 * b7)[15:0]
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or
+// unsigned 32-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Multiply the packed unsigned 16-bit integers in a and b, producing
+// intermediate 32-bit integers, and store the high 16 bits of the intermediate
+// integers in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      tmp[31:0] := a[i+15:i] * b[i+15:i]
+//      dst[i+15:i] := tmp[31:16]
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw
+#define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b)
+
+// Multiplies the four single-precision, floating-point values of a and b.
+//
+//   r0 := a0 * b0
+//   r1 := a1 * b1
+//   r2 := a2 * b2
+//   r3 := a3 * b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_f32(
+        vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Multiply packed double-precision (64-bit) floating-point elements in a and b,
+// and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd
+FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vmulq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    double *da = (double *) &a;
+    double *db = (double *) &b;
+    double c[2];
+    c[0] = da[0] * db[0];
+    c[1] = da[1] * db[1];
+    return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Multiply the lower double-precision (64-bit) floating-point element in a and
+// b, store the result in the lower element of dst, and copy the upper element
+// from a to the upper element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_sd
+FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b)
+{
+    return _mm_move_sd(a, _mm_mul_pd(a, b));
+}
+
+// Multiply the lower single-precision (32-bit) floating-point element in a and
+// b, store the result in the lower element of dst, and copy the upper 3 packed
+// elements from a to the upper elements of dst.
+//
+//   dst[31:0] := a[31:0] * b[31:0]
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss
+FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_mul_ps(a, b));
+}
+
+// Multiply the low unsigned 32-bit integers from each packed 64-bit element in
+// a and b, and store the unsigned 64-bit results in dst.
+//
+//   r0 :=  (a0 & 0xFFFFFFFF) * (b0 & 0xFFFFFFFF)
+//   r1 :=  (a2 & 0xFFFFFFFF) * (b2 & 0xFFFFFFFF)
+FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b)
+{
+    // vmull_u32 upcasts instead of masking, so we downcast.
+    uint32x2_t a_lo = vmovn_u64(vreinterpretq_u64_m128i(a));
+    uint32x2_t b_lo = vmovn_u64(vreinterpretq_u64_m128i(b));
+    return vreinterpretq_m128i_u64(vmull_u32(a_lo, b_lo));
+}
+
+// Multiply the low unsigned 32-bit integers from a and b, and store the
+// unsigned 64-bit result in dst.
+//
+//   dst[63:0] := a[31:0] * b[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32
+FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_u64(vget_low_u64(
+        vmull_u32(vreinterpret_u32_m64(a), vreinterpret_u32_m64(b))));
+}
+
+// Multiply the low signed 32-bit integers from each packed 64-bit element in
+// a and b, and store the signed 64-bit results in dst.
+//
+//   r0 :=  (int64_t)(int32_t)a0 * (int64_t)(int32_t)b0
+//   r1 :=  (int64_t)(int32_t)a2 * (int64_t)(int32_t)b2
+FORCE_INLINE __m128i _mm_mul_epi32(__m128i a, __m128i b)
+{
+    // vmull_s32 upcasts instead of masking, so we downcast.
+    int32x2_t a_lo = vmovn_s64(vreinterpretq_s64_m128i(a));
+    int32x2_t b_lo = vmovn_s64(vreinterpretq_s64_m128i(b));
+    return vreinterpretq_m128i_s64(vmull_s32(a_lo, b_lo));
+}
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit
+// integers from b.
+//
+//   r0 := (a0 * b0) + (a1 * b1)
+//   r1 := (a2 * b2) + (a3 * b3)
+//   r2 := (a4 * b4) + (a5 * b5)
+//   r3 := (a6 * b6) + (a7 * b7)
+// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b)
+{
+    int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)),
+                              vget_low_s16(vreinterpretq_s16_m128i(b)));
+    int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)),
+                               vget_high_s16(vreinterpretq_s16_m128i(b)));
+
+    int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low));
+    int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high));
+
+    return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum));
+}
+
+// Multiply packed signed 16-bit integers in a and b, producing intermediate
+// signed 32-bit integers. Shift right by 15 bits while rounding up, and store
+// the packed 16-bit integers in dst.
+//
+//   r0 := Round(((int32_t)a0 * (int32_t)b0) >> 15)
+//   r1 := Round(((int32_t)a1 * (int32_t)b1) >> 15)
+//   r2 := Round(((int32_t)a2 * (int32_t)b2) >> 15)
+//   ...
+//   r7 := Round(((int32_t)a7 * (int32_t)b7) >> 15)
+FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b)
+{
+    // Has issues due to saturation
+    // return vreinterpretq_m128i_s16(vqrdmulhq_s16(a, b));
+
+    // Multiply
+    int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)),
+                                 vget_low_s16(vreinterpretq_s16_m128i(b)));
+    int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)),
+                                 vget_high_s16(vreinterpretq_s16_m128i(b)));
+
+    // Rounding narrowing shift right
+    // narrow = (int16_t)((mul + 16384) >> 15);
+    int16x4_t narrow_lo = vrshrn_n_s32(mul_lo, 15);
+    int16x4_t narrow_hi = vrshrn_n_s32(mul_hi, 15);
+
+    // Join together
+    return vreinterpretq_m128i_s16(vcombine_s16(narrow_lo, narrow_hi));
+}
+
+// Vertically multiply each unsigned 8-bit integer from a with the corresponding
+// signed 8-bit integer from b, producing intermediate signed 16-bit integers.
+// Horizontally add adjacent pairs of intermediate signed 16-bit integers,
+// and pack the saturated results in dst.
+//
+//   FOR j := 0 to 7
+//      i := j*16
+//      dst[i+15:i] := Saturate_To_Int16( a[i+15:i+8]*b[i+15:i+8] +
+//      a[i+7:i]*b[i+7:i] )
+//   ENDFOR
+FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b)
+{
+#if defined(__aarch64__)
+    uint8x16_t a = vreinterpretq_u8_m128i(_a);
+    int8x16_t b = vreinterpretq_s8_m128i(_b);
+    int16x8_t tl = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(a))),
+                             vmovl_s8(vget_low_s8(b)));
+    int16x8_t th = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(a))),
+                             vmovl_s8(vget_high_s8(b)));
+    return vreinterpretq_m128i_s16(
+        vqaddq_s16(vuzp1q_s16(tl, th), vuzp2q_s16(tl, th)));
+#else
+    // This would be much simpler if x86 would choose to zero extend OR sign
+    // extend, not both. This could probably be optimized better.
+    uint16x8_t a = vreinterpretq_u16_m128i(_a);
+    int16x8_t b = vreinterpretq_s16_m128i(_b);
+
+    // Zero extend a
+    int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a, 8));
+    int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a, vdupq_n_u16(0xff00)));
+
+    // Sign extend by shifting left then shifting right.
+    int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b, 8), 8);
+    int16x8_t b_odd = vshrq_n_s16(b, 8);
+
+    // multiply
+    int16x8_t prod1 = vmulq_s16(a_even, b_even);
+    int16x8_t prod2 = vmulq_s16(a_odd, b_odd);
+
+    // saturated add
+    return vreinterpretq_m128i_s16(vqaddq_s16(prod1, prod2));
+#endif
+}
+
+// Computes the fused multiple add product of 32-bit floating point numbers.
+//
+// Return Value
+// Multiplies A and B, and adds C to the temporary result before returning it.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd
+FORCE_INLINE __m128 _mm_fmadd_ps(__m128 a, __m128 b, __m128 c)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(c),
+                                            vreinterpretq_f32_m128(b),
+                                            vreinterpretq_f32_m128(a)));
+#else
+    return _mm_add_ps(_mm_mul_ps(a, b), c);
+#endif
+}
+
+// Alternatively add and subtract packed single-precision (32-bit)
+// floating-point elements in a to/from packed elements in b, and store the
+// results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps
+FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b)
+{
+    __m128 mask = {-1.0f, 1.0f, -1.0f, 1.0f};
+    return _mm_fmadd_ps(b, mask, a);
+}
+
+// Horizontally add adjacent pairs of double-precision (64-bit) floating-point
+// elements in a and b, and pack the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pd
+FORCE_INLINE __m128d _mm_hadd_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vpaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    double *da = (double *) &a;
+    double *db = (double *) &b;
+    double c[] = {da[0] + da[1], db[0] + db[1]};
+    return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c));
+#endif
+}
+
+// Compute the absolute differences of packed unsigned 8-bit integers in a and
+// b, then horizontally sum each consecutive 8 differences to produce two
+// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low
+// 16 bits of 64-bit elements in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8
+FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b)
+{
+    uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b));
+    uint16_t r0 = t[0] + t[1] + t[2] + t[3];
+    uint16_t r4 = t[4] + t[5] + t[6] + t[7];
+    uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0);
+    return (__m128i) vsetq_lane_u16(r4, r, 4);
+}
+
+// Compute the absolute differences of packed unsigned 8-bit integers in a and
+// b, then horizontally sum each consecutive 8 differences to produce four
+// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low
+// 16 bits of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8
+FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b)
+{
+    uint16x4_t t =
+        vpaddl_u8(vabd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+    uint16_t r0 = t[0] + t[1] + t[2] + t[3];
+    return vreinterpret_m64_u16(vset_lane_u16(r0, vdup_n_u16(0), 0));
+}
+
+// Compute the absolute differences of packed unsigned 8-bit integers in a and
+// b, then horizontally sum each consecutive 8 differences to produce four
+// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low
+// 16 bits of dst.
+//
+//   FOR j := 0 to 7
+//      i := j*8
+//      tmp[i+7:i] := ABS(a[i+7:i] - b[i+7:i])
+//   ENDFOR
+//   dst[15:0] := tmp[7:0] + tmp[15:8] + tmp[23:16] + tmp[31:24] + tmp[39:32] +
+//   tmp[47:40] + tmp[55:48] + tmp[63:56] dst[63:16] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_psadbw
+#define _m_psadbw(a, b) _mm_sad_pu8(a, b)
+
+// Divides the four single-precision, floating-point values of a and b.
+//
+//   r0 := a0 / b0
+//   r1 := a1 / b1
+//   r2 := a2 / b2
+//   r3 := a3 / b3
+//
+// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__) && !SSE2NEON_PRECISE_DIV
+    return vreinterpretq_m128_f32(
+        vdivq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+    float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(b));
+    recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b)));
+#if SSE2NEON_PRECISE_DIV
+    // Additional Netwon-Raphson iteration for accuracy
+    recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b)));
+#endif
+    return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip));
+#endif
+}
+
+// Divides the scalar single-precision floating point value of a by b.
+// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b)
+{
+    float32_t value =
+        vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0);
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Divide packed double-precision (64-bit) floating-point elements in a by
+// packed elements in b, and store the results in dst.
+//
+//  FOR j := 0 to 1
+//    i := 64*j
+//    dst[i+63:i] := a[i+63:i] / b[i+63:i]
+//  ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_pd
+FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    double *da = (double *) &a;
+    double *db = (double *) &b;
+    double c[2];
+    c[0] = da[0] / db[0];
+    c[1] = da[1] / db[1];
+    return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Divide the lower double-precision (64-bit) floating-point element in a by the
+// lower double-precision (64-bit) floating-point element in b, store the result
+// in the lower element of dst, and copy the upper element from a to the upper
+// element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_sd
+FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    float64x2_t tmp =
+        vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b));
+    return vreinterpretq_m128d_f64(
+        vsetq_lane_f64(vgetq_lane_f64(vreinterpretq_f64_m128d(a), 1), tmp, 1));
+#else
+    return _mm_move_sd(a, _mm_div_pd(a, b));
+#endif
+}
+
+// Compute the approximate reciprocal of packed single-precision (32-bit)
+// floating-point elements in a, and store the results in dst. The maximum
+// relative error for this approximation is less than 1.5*2^-12.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps
+FORCE_INLINE __m128 _mm_rcp_ps(__m128 in)
+{
+    float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in));
+    recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));
+#if SSE2NEON_PRECISE_DIV
+    // Additional Netwon-Raphson iteration for accuracy
+    recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));
+#endif
+    return vreinterpretq_m128_f32(recip);
+}
+
+// Compute the approximate reciprocal of the lower single-precision (32-bit)
+// floating-point element in a, store the result in the lower element of dst,
+// and copy the upper 3 packed elements from a to the upper elements of dst. The
+// maximum relative error for this approximation is less than 1.5*2^-12.
+//
+//   dst[31:0] := (1.0 / a[31:0])
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss
+FORCE_INLINE __m128 _mm_rcp_ss(__m128 a)
+{
+    return _mm_move_ss(a, _mm_rcp_ps(a));
+}
+
+// Computes the approximations of square roots of the four single-precision,
+// floating-point values of a. First computes reciprocal square roots and then
+// reciprocals of the four values.
+//
+//   r0 := sqrt(a0)
+//   r1 := sqrt(a1)
+//   r2 := sqrt(a2)
+//   r3 := sqrt(a3)
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in)
+{
+#if SSE2NEON_PRECISE_SQRT
+    float32x4_t recip = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+
+    // Test for vrsqrteq_f32(0) -> positive infinity case.
+    // Change to zero, so that s * 1/sqrt(s) result is zero too.
+    const uint32x4_t pos_inf = vdupq_n_u32(0x7F800000);
+    const uint32x4_t div_by_zero =
+        vceqq_u32(pos_inf, vreinterpretq_u32_f32(recip));
+    recip = vreinterpretq_f32_u32(
+        vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(recip)));
+
+    // Additional Netwon-Raphson iteration for accuracy
+    recip = vmulq_f32(
+        vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)),
+        recip);
+    recip = vmulq_f32(
+        vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)),
+        recip);
+
+    // sqrt(s) = s * 1/sqrt(s)
+    return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(in), recip));
+#elif defined(__aarch64__)
+    return vreinterpretq_m128_f32(vsqrtq_f32(vreinterpretq_f32_m128(in)));
+#else
+    float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+    float32x4_t sq = vrecpeq_f32(recipsq);
+    return vreinterpretq_m128_f32(sq);
+#endif
+}
+
+// Computes the approximation of the square root of the scalar single-precision
+// floating point value of in.
+// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in)
+{
+    float32_t value =
+        vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0);
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0));
+}
+
+// Computes the approximations of the reciprocal square roots of the four
+// single-precision floating point values of in.
+// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in)
+{
+    float32x4_t out = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+#if SSE2NEON_PRECISE_RSQRT
+    // Additional Netwon-Raphson iteration for accuracy
+    out = vmulq_f32(
+        out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out));
+    out = vmulq_f32(
+        out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out));
+#endif
+    return vreinterpretq_m128_f32(out);
+}
+
+// Compute the approximate reciprocal square root of the lower single-precision
+// (32-bit) floating-point element in a, store the result in the lower element
+// of dst, and copy the upper 3 packed elements from a to the upper elements of
+// dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss
+FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in)
+{
+    return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0);
+}
+
+// Compare packed signed 16-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      dst[i+15:i] := MAX(a[i+15:i], b[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16
+FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_s16(
+        vmax_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b)));
+}
+
+// Compare packed signed 16-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      dst[i+15:i] := MAX(a[i+15:i], b[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16
+#define _m_pmaxsw(a, b) _mm_max_pi16(a, b)
+
+// Computes the maximums of the four single-precision, floating-point values of
+// a and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b)
+{
+#if SSE2NEON_PRECISE_MINMAX
+    float32x4_t _a = vreinterpretq_f32_m128(a);
+    float32x4_t _b = vreinterpretq_f32_m128(b);
+    return vbslq_f32(vcltq_f32(_b, _a), _a, _b);
+#else
+    return vreinterpretq_m128_f32(
+        vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#endif
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+//   FOR j := 0 to 7
+//      i := j*8
+//      dst[i+7:i] := MAX(a[i+7:i], b[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8
+FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_u8(
+        vmax_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+//   FOR j := 0 to 7
+//      i := j*8
+//      dst[i+7:i] := MAX(a[i+7:i], b[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8
+#define _m_pmaxub(a, b) _mm_max_pu8(a, b)
+
+// Compare packed signed 16-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      dst[i+15:i] := MIN(a[i+15:i], b[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16
+FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_s16(
+        vmin_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b)));
+}
+
+// Compare packed signed 16-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      dst[i+15:i] := MIN(a[i+15:i], b[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16
+#define _m_pminsw(a, b) _mm_min_pi16(a, b)
+
+// Computes the minima of the four single-precision, floating-point values of a
+// and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b)
+{
+#if SSE2NEON_PRECISE_MINMAX
+    float32x4_t _a = vreinterpretq_f32_m128(a);
+    float32x4_t _b = vreinterpretq_f32_m128(b);
+    return vbslq_f32(vcltq_f32(_a, _b), _a, _b);
+#else
+    return vreinterpretq_m128_f32(
+        vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#endif
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+//   FOR j := 0 to 7
+//      i := j*8
+//      dst[i+7:i] := MIN(a[i+7:i], b[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8
+FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_u8(
+        vmin_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+//   FOR j := 0 to 7
+//      i := j*8
+//      dst[i+7:i] := MIN(a[i+7:i], b[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8
+#define _m_pminub(a, b) _mm_min_pu8(a, b)
+
+// Computes the maximum of the two lower scalar single-precision floating point
+// values of a and b.
+// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b)
+{
+    float32_t value = vgetq_lane_f32(_mm_max_ps(a, b), 0);
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Computes the minimum of the two lower scalar single-precision floating point
+// values of a and b.
+// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b)
+{
+    float32_t value = vgetq_lane_f32(_mm_min_ps(a, b), 0);
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the
+// 16 unsigned 8-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the
+// 16 unsigned 8-bit integers from b.
+// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx
+FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8
+// signed 16-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compare packed signed 8-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8
+FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vmaxq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compare packed unsigned 16-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16
+FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vmaxq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Compare packed signed 8-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8
+FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vminq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compare packed unsigned 16-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16
+FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vminq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8
+// signed 16-bit integers from b.
+// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// epi versions of min/max
+// Computes the pariwise maximums of the four signed 32-bit integer values of a
+// and b.
+//
+// A 128-bit parameter that can be defined with the following equations:
+//   r0 := (a0 > b0) ? a0 : b0
+//   r1 := (a1 > b1) ? a1 : b1
+//   r2 := (a2 > b2) ? a2 : b2
+//   r3 := (a3 > b3) ? a3 : b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the pariwise minima of the four signed 32-bit integer values of a
+// and b.
+//
+// A 128-bit parameter that can be defined with the following equations:
+//   r0 := (a0 < b0) ? a0 : b0
+//   r1 := (a1 < b1) ? a1 : b1
+//   r2 := (a2 < b2) ? a2 : b2
+//   r3 := (a3 < b3) ? a3 : b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s32(
+        vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compare packed unsigned 32-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32
+FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u32(
+        vmaxq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)));
+}
+
+// Compare packed unsigned 32-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32
+FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u32(
+        vminq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)));
+}
+
+// Multiply the packed unsigned 16-bit integers in a and b, producing
+// intermediate 32-bit integers, and store the high 16 bits of the intermediate
+// integers in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16
+FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_u16(vshrn_n_u32(
+        vmull_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)), 16));
+}
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit
+// integers from b.
+//
+//   r0 := (a0 * b0)[31:16]
+//   r1 := (a1 * b1)[31:16]
+//   ...
+//   r7 := (a7 * b7)[31:16]
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b)
+{
+    /* FIXME: issue with large values because of result saturation */
+    // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a),
+    // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return
+    // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1));
+    int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a));
+    int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b));
+    int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */
+    int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a));
+    int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b));
+    int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */
+    uint16x8x2_t r =
+        vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654));
+    return vreinterpretq_m128i_u16(r.val[1]);
+}
+
+// Multiply the packed unsigned 16-bit integers in a and b, producing
+// intermediate 32-bit integers, and store the high 16 bits of the intermediate
+// integers in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16
+FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b)
+{
+    uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a));
+    uint16x4_t b3210 = vget_low_u16(vreinterpretq_u16_m128i(b));
+    uint32x4_t ab3210 = vmull_u16(a3210, b3210);
+#if defined(__aarch64__)
+    uint32x4_t ab7654 =
+        vmull_high_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b));
+    uint16x8_t r = vuzp2q_u16(vreinterpretq_u16_u32(ab3210),
+                              vreinterpretq_u16_u32(ab7654));
+    return vreinterpretq_m128i_u16(r);
+#else
+    uint16x4_t a7654 = vget_high_u16(vreinterpretq_u16_m128i(a));
+    uint16x4_t b7654 = vget_high_u16(vreinterpretq_u16_m128i(b));
+    uint32x4_t ab7654 = vmull_u16(a7654, b7654);
+    uint16x8x2_t r =
+        vuzpq_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654));
+    return vreinterpretq_m128i_u16(r.val[1]);
+#endif
+}
+
+// Computes pairwise add of each argument as single-precision, floating-point
+// values a and b.
+// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx
+FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128_f32(
+        vpaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_f32(
+        vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32)));
+#endif
+}
+
+// Computes pairwise add of each argument as a 16-bit signed or unsigned integer
+// values a and b.
+FORCE_INLINE __m128i _mm_hadd_epi16(__m128i _a, __m128i _b)
+{
+    int16x8_t a = vreinterpretq_s16_m128i(_a);
+    int16x8_t b = vreinterpretq_s16_m128i(_b);
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s16(vpaddq_s16(a, b));
+#else
+    return vreinterpretq_m128i_s16(
+        vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)),
+                     vpadd_s16(vget_low_s16(b), vget_high_s16(b))));
+#endif
+}
+
+// Horizontally substract adjacent pairs of single-precision (32-bit)
+// floating-point elements in a and b, and pack the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps
+FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128_f32(vsubq_f32(
+        vuzp1q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)),
+        vuzp2q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b))));
+#else
+    float32x4x2_t c =
+        vuzpq_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b));
+    return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1]));
+#endif
+}
+
+// Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the
+// signed 16-bit results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16
+FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_s16(
+        vpadd_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b)));
+}
+
+// Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the
+// signed 32-bit results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32
+FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b)
+{
+    return vreinterpret_m64_s32(
+        vpadd_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b)));
+}
+
+// Computes pairwise difference of each argument as a 16-bit signed or unsigned
+// integer values a and b.
+FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b)
+{
+    int32x4_t a = vreinterpretq_s32_m128i(_a);
+    int32x4_t b = vreinterpretq_s32_m128i(_b);
+    // Interleave using vshrn/vmovn
+    // [a0|a2|a4|a6|b0|b2|b4|b6]
+    // [a1|a3|a5|a7|b1|b3|b5|b7]
+    int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b));
+    int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16));
+    // Subtract
+    return vreinterpretq_m128i_s16(vsubq_s16(ab0246, ab1357));
+}
+
+// Computes saturated pairwise sub of each argument as a 16-bit signed
+// integer values a and b.
+FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b)
+{
+#if defined(__aarch64__)
+    int16x8_t a = vreinterpretq_s16_m128i(_a);
+    int16x8_t b = vreinterpretq_s16_m128i(_b);
+    return vreinterpretq_s64_s16(
+        vqaddq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b)));
+#else
+    int32x4_t a = vreinterpretq_s32_m128i(_a);
+    int32x4_t b = vreinterpretq_s32_m128i(_b);
+    // Interleave using vshrn/vmovn
+    // [a0|a2|a4|a6|b0|b2|b4|b6]
+    // [a1|a3|a5|a7|b1|b3|b5|b7]
+    int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b));
+    int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16));
+    // Saturated add
+    return vreinterpretq_m128i_s16(vqaddq_s16(ab0246, ab1357));
+#endif
+}
+
+// Computes saturated pairwise difference of each argument as a 16-bit signed
+// integer values a and b.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16
+FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b)
+{
+#if defined(__aarch64__)
+    int16x8_t a = vreinterpretq_s16_m128i(_a);
+    int16x8_t b = vreinterpretq_s16_m128i(_b);
+    return vreinterpretq_s64_s16(
+        vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b)));
+#else
+    int32x4_t a = vreinterpretq_s32_m128i(_a);
+    int32x4_t b = vreinterpretq_s32_m128i(_b);
+    // Interleave using vshrn/vmovn
+    // [a0|a2|a4|a6|b0|b2|b4|b6]
+    // [a1|a3|a5|a7|b1|b3|b5|b7]
+    int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b));
+    int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16));
+    // Saturated subtract
+    return vreinterpretq_m128i_s16(vqsubq_s16(ab0246, ab1357));
+#endif
+}
+
+// Computes pairwise add of each argument as a 32-bit signed or unsigned integer
+// values a and b.
+FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b)
+{
+    int32x4_t a = vreinterpretq_s32_m128i(_a);
+    int32x4_t b = vreinterpretq_s32_m128i(_b);
+    return vreinterpretq_m128i_s32(
+        vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)),
+                     vpadd_s32(vget_low_s32(b), vget_high_s32(b))));
+}
+
+// Computes pairwise difference of each argument as a 32-bit signed or unsigned
+// integer values a and b.
+FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b)
+{
+    int64x2_t a = vreinterpretq_s64_m128i(_a);
+    int64x2_t b = vreinterpretq_s64_m128i(_b);
+    // Interleave using vshrn/vmovn
+    // [a0|a2|b0|b2]
+    // [a1|a2|b1|b3]
+    int32x4_t ab02 = vcombine_s32(vmovn_s64(a), vmovn_s64(b));
+    int32x4_t ab13 = vcombine_s32(vshrn_n_s64(a, 32), vshrn_n_s64(b, 32));
+    // Subtract
+    return vreinterpretq_m128i_s32(vsubq_s32(ab02, ab13));
+}
+
+// Kahan summation for accurate summation of floating-point numbers.
+// http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html
+FORCE_INLINE void _sse2neon_kadd_f32(float *sum, float *c, float y)
+{
+    y -= *c;
+    float t = *sum + y;
+    *c = (t - *sum) - y;
+    *sum = t;
+}
+
+// Conditionally multiply the packed single-precision (32-bit) floating-point
+// elements in a and b using the high 4 bits in imm8, sum the four products,
+// and conditionally store the sum in dst using the low 4 bits of imm.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_ps
+FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm)
+{
+#if defined(__aarch64__)
+    /* shortcuts */
+    if (imm == 0xFF) {
+        return _mm_set1_ps(vaddvq_f32(_mm_mul_ps(a, b)));
+    }
+    if (imm == 0x7F) {
+        float32x4_t m = _mm_mul_ps(a, b);
+        m[3] = 0;
+        return _mm_set1_ps(vaddvq_f32(m));
+    }
+#endif
+
+    float s = 0, c = 0;
+    float32x4_t f32a = vreinterpretq_f32_m128(a);
+    float32x4_t f32b = vreinterpretq_f32_m128(b);
+
+    /* To improve the accuracy of floating-point summation, Kahan algorithm
+     * is used for each operation.
+     */
+    if (imm & (1 << 4))
+        _sse2neon_kadd_f32(&s, &c, f32a[0] * f32b[0]);
+    if (imm & (1 << 5))
+        _sse2neon_kadd_f32(&s, &c, f32a[1] * f32b[1]);
+    if (imm & (1 << 6))
+        _sse2neon_kadd_f32(&s, &c, f32a[2] * f32b[2]);
+    if (imm & (1 << 7))
+        _sse2neon_kadd_f32(&s, &c, f32a[3] * f32b[3]);
+    s += c;
+
+    float32x4_t res = {
+        (imm & 0x1) ? s : 0,
+        (imm & 0x2) ? s : 0,
+        (imm & 0x4) ? s : 0,
+        (imm & 0x8) ? s : 0,
+    };
+    return vreinterpretq_m128_f32(res);
+}
+
+/* Compare operations */
+
+// Compares for less than
+// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_u32(
+        vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for less than
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fy94wye7(v=vs.100)
+FORCE_INLINE __m128 _mm_cmplt_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmplt_ps(a, b));
+}
+
+// Compares for greater than.
+//
+//   r0 := (a0 > b0) ? 0xffffffff : 0x0
+//   r1 := (a1 > b1) ? 0xffffffff : 0x0
+//   r2 := (a2 > b2) ? 0xffffffff : 0x0
+//   r3 := (a3 > b3) ? 0xffffffff : 0x0
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_u32(
+        vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for greater than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1xyyyy9e(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpgt_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmpgt_ps(a, b));
+}
+
+// Compares for greater than or equal.
+// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_u32(
+        vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for greater than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/kesh3ddc(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpge_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmpge_ps(a, b));
+}
+
+// Compares for less than or equal.
+//
+//   r0 := (a0 <= b0) ? 0xffffffff : 0x0
+//   r1 := (a1 <= b1) ? 0xffffffff : 0x0
+//   r2 := (a2 <= b2) ? 0xffffffff : 0x0
+//   r3 := (a3 <= b3) ? 0xffffffff : 0x0
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_u32(
+        vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for less than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/a7x0hbhw(v=vs.100)
+FORCE_INLINE __m128 _mm_cmple_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmple_ps(a, b));
+}
+
+// Compares for equality.
+// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_u32(
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for equality.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/k423z28e(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpeq_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmpeq_ps(a, b));
+}
+
+// Compares for inequality.
+// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b)
+{
+    return vreinterpretq_m128_u32(vmvnq_u32(
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))));
+}
+
+// Compares for inequality.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ekya8fh4(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpneq_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmpneq_ps(a, b));
+}
+
+// Compares for not greater than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wsexys62(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnge_ps(__m128 a, __m128 b)
+{
+    return _mm_cmplt_ps(a, b);
+}
+
+// Compares for not greater than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fk2y80s8(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnge_ss(__m128 a, __m128 b)
+{
+    return _mm_cmplt_ss(a, b);
+}
+
+// Compares for not greater than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/d0xh7w0s(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpngt_ps(__m128 a, __m128 b)
+{
+    return _mm_cmple_ps(a, b);
+}
+
+// Compares for not greater than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpngt_ss(__m128 a, __m128 b)
+{
+    return _mm_cmple_ss(a, b);
+}
+
+// Compares for not less than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/6a330kxw(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b)
+{
+    return _mm_cmpgt_ps(a, b);
+}
+
+// Compares for not less than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnle_ss(__m128 a, __m128 b)
+{
+    return _mm_cmpgt_ss(a, b);
+}
+
+// Compares for not less than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/4686bbdw(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b)
+{
+    return _mm_cmpge_ps(a, b);
+}
+
+// Compares for not less than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/56b9z2wf(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnlt_ss(__m128 a, __m128 b)
+{
+    return _mm_cmpge_ss(a, b);
+}
+
+// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or
+// unsigned 8-bit integers in b for equality.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compare packed double-precision (64-bit) floating-point elements in a and b
+// for equality, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_pd
+FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_u64(
+        vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi)
+    uint32x4_t cmp =
+        vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b));
+    uint32x4_t swapped = vrev64q_u32(cmp);
+    return vreinterpretq_m128d_u32(vandq_u32(cmp, swapped));
+#endif
+}
+
+// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or
+// unsigned 16-bit integers in b for equality.
+// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compare packed 32-bit integers in a and b for equality, and store the results
+// in dst
+FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u32(
+        vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compare packed 64-bit integers in a and b for equality, and store the results
+// in dst
+FORCE_INLINE __m128i _mm_cmpeq_epi64(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_u64(
+        vceqq_u64(vreinterpretq_u64_m128i(a), vreinterpretq_u64_m128i(b)));
+#else
+    // ARMv7 lacks vceqq_u64
+    // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi)
+    uint32x4_t cmp =
+        vceqq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b));
+    uint32x4_t swapped = vrev64q_u32(cmp);
+    return vreinterpretq_m128i_u32(vandq_u32(cmp, swapped));
+#endif
+}
+
+// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers
+// in b for lesser than.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers
+// in b for greater than.
+//
+//   r0 := (a0 > b0) ? 0xff : 0x0
+//   r1 := (a1 > b1) ? 0xff : 0x0
+//   ...
+//   r15 := (a15 > b15) ? 0xff : 0x0
+//
+// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers
+// in b for less than.
+//
+//   r0 := (a0 < b0) ? 0xffff : 0x0
+//   r1 := (a1 < b1) ? 0xffff : 0x0
+//   ...
+//   r7 := (a7 < b7) ? 0xffff : 0x0
+//
+// https://technet.microsoft.com/en-us/library/t863edb2(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers
+// in b for greater than.
+//
+//   r0 := (a0 > b0) ? 0xffff : 0x0
+//   r1 := (a1 > b1) ? 0xffff : 0x0
+//   ...
+//   r7 := (a7 > b7) ? 0xffff : 0x0
+//
+// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers
+// in b for less than.
+// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u32(
+        vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers
+// in b for greater than.
+// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u32(
+        vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers
+// in b for greater than.
+FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_u64(
+        vcgtq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+#else
+    // ARMv7 lacks vcgtq_s64.
+    // This is based off of Clang's SSE2 polyfill:
+    // (a > b) -> ((a_hi > b_hi) || (a_lo > b_lo && a_hi == b_hi))
+
+    // Mask the sign bit out since we need a signed AND an unsigned comparison
+    // and it is ugly to try and split them.
+    int32x4_t mask = vreinterpretq_s32_s64(vdupq_n_s64(0x80000000ull));
+    int32x4_t a_mask = veorq_s32(vreinterpretq_s32_m128i(a), mask);
+    int32x4_t b_mask = veorq_s32(vreinterpretq_s32_m128i(b), mask);
+    // Check if a > b
+    int64x2_t greater = vreinterpretq_s64_u32(vcgtq_s32(a_mask, b_mask));
+    // Copy upper mask to lower mask
+    // a_hi > b_hi
+    int64x2_t gt_hi = vshrq_n_s64(greater, 63);
+    // Copy lower mask to upper mask
+    // a_lo > b_lo
+    int64x2_t gt_lo = vsliq_n_s64(greater, greater, 32);
+    // Compare for equality
+    int64x2_t equal = vreinterpretq_s64_u32(vceqq_s32(a_mask, b_mask));
+    // Copy upper mask to lower mask
+    // a_hi == b_hi
+    int64x2_t eq_hi = vshrq_n_s64(equal, 63);
+    // a_hi > b_hi || (a_lo > b_lo && a_hi == b_hi)
+    int64x2_t ret = vorrq_s64(gt_hi, vandq_s64(gt_lo, eq_hi));
+    return vreinterpretq_m128i_s64(ret);
+#endif
+}
+
+// Compares the four 32-bit floats in a and b to check if any values are NaN.
+// Ordered compare between each value returns true for "orderable" and false for
+// "not orderable" (NaN).
+// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see
+// also:
+// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean
+// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics
+FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b)
+{
+    // Note: NEON does not have ordered compare builtin
+    // Need to compare a eq a and b eq b to check for NaN
+    // Do AND of results to get final
+    uint32x4_t ceqaa =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t ceqbb =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb));
+}
+
+// Compares for ordered.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/343t62da(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpord_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmpord_ps(a, b));
+}
+
+// Compares for unordered.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/khy6fk1t(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 a, __m128 b)
+{
+    uint32x4_t f32a =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t f32b =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    return vreinterpretq_m128_u32(vmvnq_u32(vandq_u32(f32a, f32b)));
+}
+
+// Compares for unordered.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/2as2387b(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpunord_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(a, _mm_cmpunord_ps(a, b));
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a less than operation. :
+// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important
+// note!! The documentation on MSDN is incorrect!  If either of the values is a
+// NAN the docs say you will get a one, but in fact, it will return a zero!!
+FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b)
+{
+    uint32x4_t a_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t b_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+    uint32x4_t a_lt_b =
+        vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_lt_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a greater than operation. :
+// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx
+FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b)
+{
+    // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a),
+    // vreinterpretq_f32_m128(b)), 0);
+    uint32x4_t a_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t b_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+    uint32x4_t a_gt_b =
+        vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a less than or equal operation. :
+// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx
+FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b)
+{
+    // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a),
+    // vreinterpretq_f32_m128(b)), 0);
+    uint32x4_t a_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t b_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+    uint32x4_t a_le_b =
+        vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_le_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a greater than or equal operation. :
+// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx
+FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b)
+{
+    // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a),
+    // vreinterpretq_f32_m128(b)), 0);
+    uint32x4_t a_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t b_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+    uint32x4_t a_ge_b =
+        vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using an equality operation. :
+// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx
+FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b)
+{
+    // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),
+    // vreinterpretq_f32_m128(b)), 0);
+    uint32x4_t a_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t b_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+    uint32x4_t a_eq_b =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_eq_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using an inequality operation. :
+// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx
+FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b)
+{
+    // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),
+    // vreinterpretq_f32_m128(b)), 0);
+    uint32x4_t a_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+    uint32x4_t b_not_nan =
+        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+    uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan));
+    uint32x4_t a_neq_b = vmvnq_u32(
+        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+    return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_neq_b), 0) != 0) ? 1 : 0;
+}
+
+// according to the documentation, these intrinsics behave the same as the
+// non-'u' versions.  We'll just alias them here.
+#define _mm_ucomieq_ss _mm_comieq_ss
+#define _mm_ucomige_ss _mm_comige_ss
+#define _mm_ucomigt_ss _mm_comigt_ss
+#define _mm_ucomile_ss _mm_comile_ss
+#define _mm_ucomilt_ss _mm_comilt_ss
+#define _mm_ucomineq_ss _mm_comineq_ss
+
+/* Conversions */
+
+// Convert packed signed 32-bit integers in b to packed single-precision
+// (32-bit) floating-point elements, store the results in the lower 2 elements
+// of dst, and copy the upper 2 packed elements from a to the upper elements of
+// dst.
+//
+//   dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+//   dst[63:32] := Convert_Int32_To_FP32(b[63:32])
+//   dst[95:64] := a[95:64]
+//   dst[127:96] := a[127:96]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps
+FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b)
+{
+    return vreinterpretq_m128_f32(
+        vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)),
+                     vget_high_f32(vreinterpretq_f32_m128(a))));
+}
+
+// Convert the signed 32-bit integer b to a single-precision (32-bit)
+// floating-point element, store the result in the lower element of dst, and
+// copy the upper 3 packed elements from a to the upper elements of dst.
+//
+//   dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss
+FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b)
+{
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0));
+}
+
+// Convert the signed 32-bit integer b to a single-precision (32-bit)
+// floating-point element, store the result in the lower element of dst, and
+// copy the upper 3 packed elements from a to the upper elements of dst.
+//
+//   dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss
+#define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b)
+
+// Convert the signed 64-bit integer b to a single-precision (32-bit)
+// floating-point element, store the result in the lower element of dst, and
+// copy the upper 3 packed elements from a to the upper elements of dst.
+//
+//   dst[31:0] := Convert_Int64_To_FP32(b[63:0])
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss
+FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b)
+{
+    return vreinterpretq_m128_f32(
+        vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0));
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer, and store the result in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si
+FORCE_INLINE int _mm_cvt_ss2si(__m128 a)
+{
+#if defined(__aarch64__)
+    return vgetq_lane_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a)), 0);
+#else
+    float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+    float32_t diff = data - floor(data);
+    if (diff > 0.5)
+        return (int32_t) ceil(data);
+    if (unlikely(diff == 0.5)) {
+        int32_t f = (int32_t) floor(data);
+        int32_t c = (int32_t) ceil(data);
+        return c & 1 ? f : c;
+    }
+    return (int32_t) floor(data);
+#endif
+}
+
+// Convert packed 16-bit integers in a to packed single-precision (32-bit)
+// floating-point elements, and store the results in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      m := j*32
+//      dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps
+FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a)
+{
+    return vreinterpretq_m128_f32(
+        vcvtq_f32_s32(vmovl_s16(vreinterpret_s16_m64(a))));
+}
+
+// Convert packed 32-bit integers in b to packed single-precision (32-bit)
+// floating-point elements, store the results in the lower 2 elements of dst,
+// and copy the upper 2 packed elements from a to the upper elements of dst.
+//
+//   dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+//   dst[63:32] := Convert_Int32_To_FP32(b[63:32])
+//   dst[95:64] := a[95:64]
+//   dst[127:96] := a[127:96]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps
+FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b)
+{
+    return vreinterpretq_m128_f32(
+        vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)),
+                     vget_high_f32(vreinterpretq_f32_m128(a))));
+}
+
+// Convert packed signed 32-bit integers in a to packed single-precision
+// (32-bit) floating-point elements, store the results in the lower 2 elements
+// of dst, then covert the packed signed 32-bit integers in b to
+// single-precision (32-bit) floating-point element, and store the results in
+// the upper 2 elements of dst.
+//
+//   dst[31:0] := Convert_Int32_To_FP32(a[31:0])
+//   dst[63:32] := Convert_Int32_To_FP32(a[63:32])
+//   dst[95:64] := Convert_Int32_To_FP32(b[31:0])
+//   dst[127:96] := Convert_Int32_To_FP32(b[63:32])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps
+FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b)
+{
+    return vreinterpretq_m128_f32(vcvtq_f32_s32(
+        vcombine_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b))));
+}
+
+// Convert the lower packed 8-bit integers in a to packed single-precision
+// (32-bit) floating-point elements, and store the results in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*8
+//      m := j*32
+//      dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps
+FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a)
+{
+    return vreinterpretq_m128_f32(vcvtq_f32_s32(
+        vmovl_s16(vget_low_s16(vmovl_s8(vreinterpret_s8_m64(a))))));
+}
+
+// Convert packed unsigned 16-bit integers in a to packed single-precision
+// (32-bit) floating-point elements, and store the results in dst.
+//
+//   FOR j := 0 to 3
+//      i := j*16
+//      m := j*32
+//      dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps
+FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a)
+{
+    return vreinterpretq_m128_f32(
+        vcvtq_f32_u32(vmovl_u16(vreinterpret_u16_m64(a))));
+}
+
+// Convert the lower packed unsigned 8-bit integers in a to packed
+// single-precision (32-bit) floating-point elements, and store the results in
+// dst.
+//
+//   FOR j := 0 to 3
+//      i := j*8
+//      m := j*32
+//      dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps
+FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a)
+{
+    return vreinterpretq_m128_f32(vcvtq_f32_u32(
+        vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_m64(a))))));
+}
+
+// Converts the four single-precision, floating-point values of a to signed
+// 32-bit integer values using truncate.
+// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a)
+{
+    return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)));
+}
+
+// Convert the lower double-precision (64-bit) floating-point element in a to a
+// 64-bit integer with truncation, and store the result in dst.
+//
+//   dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64
+FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a)
+{
+#if defined(__aarch64__)
+    return vgetq_lane_s64(vcvtq_s64_f64(vreinterpretq_f64_m128d(a)), 0);
+#else
+    double ret = *((double *) &a);
+    return (int64_t) ret;
+#endif
+}
+
+// Convert the lower double-precision (64-bit) floating-point element in a to a
+// 64-bit integer with truncation, and store the result in dst.
+//
+//   dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x
+#define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a)
+
+// Converts the four signed 32-bit integer values of a to single-precision,
+// floating-point values
+// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a)
+{
+    return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a)));
+}
+
+// Converts the four unsigned 8-bit integers in the lower 16 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a)
+{
+    uint8x16_t u8x16 = vreinterpretq_u8_m128i(a);    /* xxxx xxxx xxxx DCBA */
+    uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+    return vreinterpretq_m128i_u16(u16x8);
+}
+
+// Converts the four unsigned 8-bit integers in the lower 32 bits to four
+// unsigned 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx
+FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a)
+{
+    uint8x16_t u8x16 = vreinterpretq_u8_m128i(a);      /* xxxx xxxx xxxx DCBA */
+    uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16));   /* 0x0x 0x0x 0D0C 0B0A */
+    uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */
+    return vreinterpretq_m128i_u32(u32x4);
+}
+
+// Converts the two unsigned 8-bit integers in the lower 16 bits to two
+// unsigned 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a)
+{
+    uint8x16_t u8x16 = vreinterpretq_u8_m128i(a);      /* xxxx xxxx xxxx xxBA */
+    uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16));   /* 0x0x 0x0x 0x0x 0B0A */
+    uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */
+    uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */
+    return vreinterpretq_m128i_u64(u64x2);
+}
+
+// Converts the four unsigned 8-bit integers in the lower 16 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi8_epi16(__m128i a)
+{
+    int8x16_t s8x16 = vreinterpretq_s8_m128i(a);    /* xxxx xxxx xxxx DCBA */
+    int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+    return vreinterpretq_m128i_s16(s16x8);
+}
+
+// Converts the four unsigned 8-bit integers in the lower 32 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi8_epi32(__m128i a)
+{
+    int8x16_t s8x16 = vreinterpretq_s8_m128i(a);      /* xxxx xxxx xxxx DCBA */
+    int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16));   /* 0x0x 0x0x 0D0C 0B0A */
+    int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000D 000C 000B 000A */
+    return vreinterpretq_m128i_s32(s32x4);
+}
+
+// Converts the two signed 8-bit integers in the lower 32 bits to four
+// signed 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi8_epi64(__m128i a)
+{
+    int8x16_t s8x16 = vreinterpretq_s8_m128i(a);      /* xxxx xxxx xxxx xxBA */
+    int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16));   /* 0x0x 0x0x 0x0x 0B0A */
+    int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */
+    int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */
+    return vreinterpretq_m128i_s64(s64x2);
+}
+
+// Converts the four signed 16-bit integers in the lower 64 bits to four signed
+// 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a)
+{
+    return vreinterpretq_m128i_s32(
+        vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a))));
+}
+
+// Converts the two signed 16-bit integers in the lower 32 bits two signed
+// 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi16_epi64(__m128i a)
+{
+    int16x8_t s16x8 = vreinterpretq_s16_m128i(a);     /* xxxx xxxx xxxx 0B0A */
+    int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */
+    int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */
+    return vreinterpretq_m128i_s64(s64x2);
+}
+
+// Converts the four unsigned 16-bit integers in the lower 64 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu16_epi32(__m128i a)
+{
+    return vreinterpretq_m128i_u32(
+        vmovl_u16(vget_low_u16(vreinterpretq_u16_m128i(a))));
+}
+
+// Converts the two unsigned 16-bit integers in the lower 32 bits to two
+// unsigned 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu16_epi64(__m128i a)
+{
+    uint16x8_t u16x8 = vreinterpretq_u16_m128i(a);     /* xxxx xxxx xxxx 0B0A */
+    uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */
+    uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */
+    return vreinterpretq_m128i_u64(u64x2);
+}
+
+// Converts the two unsigned 32-bit integers in the lower 64 bits to two
+// unsigned 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a)
+{
+    return vreinterpretq_m128i_u64(
+        vmovl_u32(vget_low_u32(vreinterpretq_u32_m128i(a))));
+}
+
+// Converts the two signed 32-bit integers in the lower 64 bits to two signed
+// 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi32_epi64(__m128i a)
+{
+    return vreinterpretq_m128i_s64(
+        vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a))));
+}
+
+// Converts the four single-precision, floating-point values of a to signed
+// 32-bit integer values.
+//
+//   r0 := (int) a0
+//   r1 := (int) a1
+//   r2 := (int) a2
+//   r3 := (int) a3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx
+// *NOTE*. The default rounding mode on SSE is 'round to even', which ARMv7-A
+// does not support! It is supported on ARMv8-A however.
+FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a));
+#else
+    uint32x4_t signmask = vdupq_n_u32(0x80000000);
+    float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a),
+                                 vdupq_n_f32(0.5f)); /* +/- 0.5 */
+    int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32(
+        vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/
+    int32x4_t r_trunc =
+        vcvtq_s32_f32(vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */
+    int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32(
+        vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */
+    int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone),
+                                 vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */
+    float32x4_t delta = vsubq_f32(
+        vreinterpretq_f32_m128(a),
+        vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */
+    uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */
+    return vreinterpretq_m128i_s32(vbslq_s32(is_delta_half, r_even, r_normal));
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 16-bit integers, and store the results in dst. Note: this intrinsic
+// will generate 0x7FFF, rather than 0x8000, for input values between 0x7FFF and
+// 0x7FFFFFFF.
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi16
+FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a)
+{
+    return vreinterpret_m64_s16(
+        vmovn_s32(vreinterpretq_s32_m128i(_mm_cvtps_epi32(a))));
+}
+
+// Copy the lower 32-bit integer in a to dst.
+//
+//   dst[31:0] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32
+FORCE_INLINE int _mm_cvtsi128_si32(__m128i a)
+{
+    return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0);
+}
+
+// Copy the lower 64-bit integer in a to dst.
+//
+//   dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64
+FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a)
+{
+    return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0);
+}
+
+// Copy the lower 64-bit integer in a to dst.
+//
+//   dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x
+#define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a)
+
+// Moves 32-bit integer a to the least significant 32 bits of an __m128 object,
+// zero extending the upper bits.
+//
+//   r0 := a
+//   r1 := 0x0
+//   r2 := 0x0
+//   r3 := 0x0
+//
+// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_cvtsi32_si128(int a)
+{
+    return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0));
+}
+
+// Moves 64-bit integer a to the least significant 64 bits of an __m128 object,
+// zero extending the upper bits.
+//
+//   r0 := a
+//   r1 := 0x0
+FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a)
+{
+    return vreinterpretq_m128i_s64(vsetq_lane_s64(a, vdupq_n_s64(0), 0));
+}
+
+// Cast vector of type __m128 to type __m128d. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd
+FORCE_INLINE __m128d _mm_castps_pd(__m128 a)
+{
+    return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a));
+}
+
+// Applies a type cast to reinterpret four 32-bit floating point values passed
+// in as a 128-bit parameter as packed 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb514099.aspx
+FORCE_INLINE __m128i _mm_castps_si128(__m128 a)
+{
+    return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a));
+}
+
+// Cast vector of type __m128i to type __m128d. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castsi128_pd
+FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vreinterpretq_f64_m128i(a));
+#else
+    return vreinterpretq_m128d_f32(vreinterpretq_f32_m128i(a));
+#endif
+}
+
+// Applies a type cast to reinterpret four 32-bit integers passed in as a
+// 128-bit parameter as packed 32-bit floating point values.
+// https://msdn.microsoft.com/en-us/library/bb514029.aspx
+FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a)
+{
+    return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a));
+}
+
+// Loads 128-bit value. :
+// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx
+FORCE_INLINE __m128i _mm_load_si128(const __m128i *p)
+{
+    return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd
+FORCE_INLINE __m128d _mm_load1_pd(const double *p)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(vld1q_dup_f64(p));
+#else
+    return vreinterpretq_m128d_s64(vdupq_n_s64(*(const int64_t *) p));
+#endif
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1
+#define _mm_load_pd1 _mm_load1_pd
+
+// Load a double-precision (64-bit) floating-point element from memory into the
+// upper element of dst, and copy the lower element from a to dst. mem_addr does
+// not need to be aligned on any particular boundary.
+//
+//   dst[63:0] := a[63:0]
+//   dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd
+FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vcombine_f64(vget_low_f64(vreinterpretq_f64_m128d(a)), vld1_f64(p)));
+#else
+    return vreinterpretq_m128d_f32(vcombine_f32(
+        vget_low_f32(vreinterpretq_f32_m128d(a)), vld1_f32((const float *) p)));
+#endif
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1
+#define _mm_load_pd1 _mm_load1_pd
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+//   dst[63:0] := MEM[mem_addr+63:mem_addr]
+//   dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd
+#define _mm_loaddup_pd _mm_load1_pd
+
+// Loads 128-bit value. :
+// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p)
+{
+    return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));
+}
+
+// Load unaligned 32-bit integer from memory into the first element of dst.
+//
+//   dst[31:0] := MEM[mem_addr+31:mem_addr]
+//   dst[MAX:32] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32
+FORCE_INLINE __m128i _mm_loadu_si32(const void *p)
+{
+    return vreinterpretq_m128i_s32(
+        vsetq_lane_s32(*(const int32_t *) p, vdupq_n_s32(0), 0));
+}
+
+// Convert packed double-precision (64-bit) floating-point elements in a to
+// packed single-precision (32-bit) floating-point elements, and store the
+// results in dst.
+//
+//   FOR j := 0 to 1
+//     i := 32*j
+//     k := 64*j
+//     dst[i+31:i] := Convert_FP64_To_FP32(a[k+64:k])
+//   ENDFOR
+//   dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps
+FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a)
+{
+#if defined(__aarch64__)
+    float32x2_t tmp = vcvt_f32_f64(vreinterpretq_f64_m128d(a));
+    return vreinterpretq_m128_f32(vcombine_f32(tmp, vdup_n_f32(0)));
+#else
+    float a0 = (float) ((double *) &a)[0];
+    float a1 = (float) ((double *) &a)[1];
+    return _mm_set_ps(0, 0, a1, a0);
+#endif
+}
+
+// Copy the lower double-precision (64-bit) floating-point element of a to dst.
+//
+//   dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64
+FORCE_INLINE double _mm_cvtsd_f64(__m128d a)
+{
+#if defined(__aarch64__)
+    return (double) vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0);
+#else
+    return ((double *) &a)[0];
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed double-precision (64-bit) floating-point elements, and store the
+// results in dst.
+//
+//   FOR j := 0 to 1
+//     i := 64*j
+//     k := 32*j
+//     dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd
+FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vcvt_f64_f32(vget_low_f32(vreinterpretq_f32_m128(a))));
+#else
+    double a0 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+    double a1 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 1);
+    return _mm_set_pd(a1, a0);
+#endif
+}
+
+// Cast vector of type __m128d to type __m128i. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128
+FORCE_INLINE __m128i _mm_castpd_si128(__m128d a)
+{
+    return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a));
+}
+
+// Cast vector of type __m128d to type __m128. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_ps
+FORCE_INLINE __m128 _mm_castpd_ps(__m128d a)
+{
+    return vreinterpretq_m128_s64(vreinterpretq_s64_m128d(a));
+}
+
+// Blend packed single-precision (32-bit) floating-point elements from a and b
+// using mask, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps
+FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask)
+{
+    // Use a signed shift right to create a mask with the sign bit
+    uint32x4_t mask =
+        vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_m128(_mask), 31));
+    float32x4_t a = vreinterpretq_f32_m128(_a);
+    float32x4_t b = vreinterpretq_f32_m128(_b);
+    return vreinterpretq_m128_f32(vbslq_f32(mask, b, a));
+}
+
+// Blend packed single-precision (32-bit) floating-point elements from a and b
+// using mask, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_ps
+FORCE_INLINE __m128 _mm_blend_ps(__m128 _a, __m128 _b, const char imm8)
+{
+    const uint32_t ALIGN_STRUCT(16)
+        data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0,
+                   ((imm8) & (1 << 1)) ? UINT32_MAX : 0,
+                   ((imm8) & (1 << 2)) ? UINT32_MAX : 0,
+                   ((imm8) & (1 << 3)) ? UINT32_MAX : 0};
+    uint32x4_t mask = vld1q_u32(data);
+    float32x4_t a = vreinterpretq_f32_m128(_a);
+    float32x4_t b = vreinterpretq_f32_m128(_b);
+    return vreinterpretq_m128_f32(vbslq_f32(mask, b, a));
+}
+
+// Blend packed double-precision (64-bit) floating-point elements from a and b
+// using mask, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_pd
+FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask)
+{
+    uint64x2_t mask =
+        vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_m128d(_mask), 63));
+#if defined(__aarch64__)
+    float64x2_t a = vreinterpretq_f64_m128d(_a);
+    float64x2_t b = vreinterpretq_f64_m128d(_b);
+    return vreinterpretq_m128d_f64(vbslq_f64(mask, b, a));
+#else
+    uint64x2_t a = vreinterpretq_u64_m128d(_a);
+    uint64x2_t b = vreinterpretq_u64_m128d(_b);
+    return vreinterpretq_m128d_u64(vbslq_u64(mask, b, a));
+#endif
+}
+
+typedef struct {
+    uint16_t res0;
+    uint8_t res1 : 6;
+    uint8_t bit22 : 1;
+    uint8_t bit23 : 1;
+    uint8_t res2;
+#if defined(__aarch64__)
+    uint32_t res3;
+#endif
+} fpcr_bitfield;
+
+// Macro: Set the rounding mode bits of the MXCSR control and status register to
+// the value in unsigned 32-bit integer a. The rounding mode may contain any of
+// the following flags: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP,
+// _MM_ROUND_TOWARD_ZERO
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_ROUNDING_MODE
+FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding)
+{
+    union {
+        fpcr_bitfield field;
+#if defined(__aarch64__)
+        uint64_t value;
+#else
+        uint32_t value;
+#endif
+    } r;
+
+#if defined(__aarch64__)
+    asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */
+#else
+    asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */
+#endif
+
+    switch (rounding) {
+    case _MM_ROUND_TOWARD_ZERO:
+        r.field.bit22 = 1;
+        r.field.bit23 = 1;
+        break;
+    case _MM_ROUND_DOWN:
+        r.field.bit22 = 0;
+        r.field.bit23 = 1;
+        break;
+    case _MM_ROUND_UP:
+        r.field.bit22 = 1;
+        r.field.bit23 = 0;
+        break;
+    default:  //_MM_ROUND_NEAREST
+        r.field.bit22 = 0;
+        r.field.bit23 = 0;
+    }
+
+#if defined(__aarch64__)
+    asm volatile("msr FPCR, %0" ::"r"(r)); /* write */
+#else
+    asm volatile("vmsr FPSCR, %0" ::"r"(r));        /* write */
+#endif
+}
+
+FORCE_INLINE void _mm_setcsr(unsigned int a)
+{
+    _MM_SET_ROUNDING_MODE(a);
+}
+
+// Round the packed single-precision (32-bit) floating-point elements in a using
+// the rounding parameter, and store the results as packed single-precision
+// floating-point elements in dst.
+// software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps
+FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding)
+{
+#if defined(__aarch64__)
+    switch (rounding) {
+    case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC):
+        return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a)));
+    case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC):
+        return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a)));
+    case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC):
+        return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a)));
+    case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC):
+        return vreinterpretq_m128_f32(vrndq_f32(vreinterpretq_f32_m128(a)));
+    default:  //_MM_FROUND_CUR_DIRECTION
+        return vreinterpretq_m128_f32(vrndiq_f32(vreinterpretq_f32_m128(a)));
+    }
+#else
+    float *v_float = (float *) &a;
+    __m128 zero, neg_inf, pos_inf;
+
+    switch (rounding) {
+    case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC):
+        return _mm_cvtepi32_ps(_mm_cvtps_epi32(a));
+    case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC):
+        return (__m128){floorf(v_float[0]), floorf(v_float[1]),
+                        floorf(v_float[2]), floorf(v_float[3])};
+    case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC):
+        return (__m128){ceilf(v_float[0]), ceilf(v_float[1]), ceilf(v_float[2]),
+                        ceilf(v_float[3])};
+    case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC):
+        zero = _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f);
+        neg_inf = _mm_set_ps(floorf(v_float[0]), floorf(v_float[1]),
+                             floorf(v_float[2]), floorf(v_float[3]));
+        pos_inf = _mm_set_ps(ceilf(v_float[0]), ceilf(v_float[1]),
+                             ceilf(v_float[2]), ceilf(v_float[3]));
+        return _mm_blendv_ps(pos_inf, neg_inf, _mm_cmple_ps(a, zero));
+    default:  //_MM_FROUND_CUR_DIRECTION
+        return (__m128){roundf(v_float[0]), roundf(v_float[1]),
+                        roundf(v_float[2]), roundf(v_float[3])};
+    }
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers, and store the results in dst.
+//
+//   FOR j := 0 to 1
+//       i := 32*j
+//       dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi
+FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a)
+{
+#if defined(__aarch64__)
+    return vreinterpret_m64_s32(
+        vget_low_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a))));
+#else
+    return vreinterpret_m64_s32(
+        vcvt_s32_f32(vget_low_f32(vreinterpretq_f32_m128(
+            _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)))));
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers, and store the results in dst.
+//
+//   FOR j := 0 to 1
+//       i := 32*j
+//       dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i])
+//   ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi32
+#define _mm_cvtps_pi32(a) _mm_cvt_ps2pi(a)
+
+// Round the packed single-precision (32-bit) floating-point elements in a up to
+// an integer value, and store the results as packed single-precision
+// floating-point elements in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps
+FORCE_INLINE __m128 _mm_ceil_ps(__m128 a)
+{
+    return _mm_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC);
+}
+
+// Round the lower single-precision (32-bit) floating-point element in b up to
+// an integer value, store the result as a single-precision floating-point
+// element in the lower element of dst, and copy the upper 3 packed elements
+// from a to the upper elements of dst.
+//
+//   dst[31:0] := CEIL(b[31:0])
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ss
+FORCE_INLINE __m128 _mm_ceil_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(
+        a, _mm_round_ps(b, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC));
+}
+
+// Round the packed single-precision (32-bit) floating-point elements in a down
+// to an integer value, and store the results as packed single-precision
+// floating-point elements in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ps
+FORCE_INLINE __m128 _mm_floor_ps(__m128 a)
+{
+    return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC);
+}
+
+// Round the lower single-precision (32-bit) floating-point element in b down to
+// an integer value, store the result as a single-precision floating-point
+// element in the lower element of dst, and copy the upper 3 packed elements
+// from a to the upper elements of dst.
+//
+//   dst[31:0] := FLOOR(b[31:0])
+//   dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ss
+FORCE_INLINE __m128 _mm_floor_ss(__m128 a, __m128 b)
+{
+    return _mm_move_ss(
+        a, _mm_round_ps(b, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC));
+}
+
+// Load 128-bits of integer data from unaligned memory into dst. This intrinsic
+// may perform better than _mm_loadu_si128 when the data crosses a cache line
+// boundary.
+//
+//   dst[127:0] := MEM[mem_addr+127:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128
+#define _mm_lddqu_si128 _mm_loadu_si128
+
+/* Miscellaneous Operations */
+
+// Shifts the 8 signed 16-bit integers in a right by count bits while shifting
+// in the sign bit.
+//
+//   r0 := a0 >> count
+//   r1 := a1 >> count
+//   ...
+//   r7 := a7 >> count
+//
+// https://msdn.microsoft.com/en-us/library/3c9997dk(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count)
+{
+    int64_t c = (int64_t) vget_low_s64((int64x2_t) count);
+    if (unlikely(c > 15))
+        return _mm_cmplt_epi16(a, _mm_setzero_si128());
+    return vreinterpretq_m128i_s16(vshlq_s16((int16x8_t) a, vdupq_n_s16(-c)));
+}
+
+// Shifts the 4 signed 32-bit integers in a right by count bits while shifting
+// in the sign bit.
+//
+//   r0 := a0 >> count
+//   r1 := a1 >> count
+//   r2 := a2 >> count
+//   r3 := a3 >> count
+//
+// https://msdn.microsoft.com/en-us/library/ce40009e(v%3dvs.100).aspx
+FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count)
+{
+    int64_t c = (int64_t) vget_low_s64((int64x2_t) count);
+    if (unlikely(c > 31))
+        return _mm_cmplt_epi32(a, _mm_setzero_si128());
+    return vreinterpretq_m128i_s32(vshlq_s32((int32x4_t) a, vdupq_n_s32(-c)));
+}
+
+// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and
+// saturates.
+// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s8(
+        vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)),
+                    vqmovn_s16(vreinterpretq_s16_m128i(b))));
+}
+
+// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned
+// integers and saturates.
+//
+//   r0 := UnsignedSaturate(a0)
+//   r1 := UnsignedSaturate(a1)
+//   ...
+//   r7 := UnsignedSaturate(a7)
+//   r8 := UnsignedSaturate(b0)
+//   r9 := UnsignedSaturate(b1)
+//   ...
+//   r15 := UnsignedSaturate(b7)
+//
+// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)),
+                    vqmovun_s16(vreinterpretq_s16_m128i(b))));
+}
+
+// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers
+// and saturates.
+//
+//   r0 := SignedSaturate(a0)
+//   r1 := SignedSaturate(a1)
+//   r2 := SignedSaturate(a2)
+//   r3 := SignedSaturate(a3)
+//   r4 := SignedSaturate(b0)
+//   r5 := SignedSaturate(b1)
+//   r6 := SignedSaturate(b2)
+//   r7 := SignedSaturate(b3)
+//
+// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_s16(
+        vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)),
+                     vqmovn_s32(vreinterpretq_s32_m128i(b))));
+}
+
+// Packs the 8 unsigned 32-bit integers from a and b into unsigned 16-bit
+// integers and saturates.
+//
+//   r0 := UnsignedSaturate(a0)
+//   r1 := UnsignedSaturate(a1)
+//   r2 := UnsignedSaturate(a2)
+//   r3 := UnsignedSaturate(a3)
+//   r4 := UnsignedSaturate(b0)
+//   r5 := UnsignedSaturate(b1)
+//   r6 := UnsignedSaturate(b2)
+//   r7 := UnsignedSaturate(b3)
+FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u16(
+        vcombine_u16(vqmovun_s32(vreinterpretq_s32_m128i(a)),
+                     vqmovun_s32(vreinterpretq_s32_m128i(b))));
+}
+
+// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower
+// 8 signed or unsigned 8-bit integers in b.
+//
+//   r0 := a0
+//   r1 := b0
+//   r2 := a1
+//   r3 := b1
+//   ...
+//   r14 := a7
+//   r15 := b7
+//
+// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s8(
+        vzip1q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+#else
+    int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a)));
+    int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b)));
+    int8x8x2_t result = vzip_s8(a1, b1);
+    return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the
+// lower 4 signed or unsigned 16-bit integers in b.
+//
+//   r0 := a0
+//   r1 := b0
+//   r2 := a1
+//   r3 := b1
+//   r4 := a2
+//   r5 := b2
+//   r6 := a3
+//   r7 := b3
+//
+// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s16(
+        vzip1q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+#else
+    int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a));
+    int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b));
+    int16x4x2_t result = vzip_s16(a1, b1);
+    return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the
+// lower 2 signed or unsigned 32 - bit integers in b.
+//
+//   r0 := a0
+//   r1 := b0
+//   r2 := a1
+//   r3 := b1
+//
+// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s32(
+        vzip1q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+#else
+    int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a));
+    int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b));
+    int32x2x2_t result = vzip_s32(a1, b1);
+    return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));
+#endif
+}
+
+FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)
+{
+    int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a));
+    int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b));
+    return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l));
+}
+
+// Selects and interleaves the lower two single-precision, floating-point values
+// from a and b.
+//
+//   r0 := a0
+//   r1 := b0
+//   r2 := a1
+//   r3 := b1
+//
+// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128_f32(
+        vzip1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+    float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a));
+    float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b));
+    float32x2x2_t result = vzip_f32(a1, b1);
+    return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));
+#endif
+}
+
+// Unpack and interleave double-precision (64-bit) floating-point elements from
+// the low half of a and b, and store the results in dst.
+//
+//   DEFINE INTERLEAVE_QWORDS(src1[127:0], src2[127:0]) {
+//     dst[63:0] := src1[63:0]
+//     dst[127:64] := src2[63:0]
+//     RETURN dst[127:0]
+//   }
+//   dst[127:0] := INTERLEAVE_QWORDS(a[127:0], b[127:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpacklo_pd
+FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vzip1q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    return vreinterpretq_m128d_s64(
+        vcombine_s64(vget_low_s64(vreinterpretq_s64_m128d(a)),
+                     vget_low_s64(vreinterpretq_s64_m128d(b))));
+#endif
+}
+
+// Unpack and interleave double-precision (64-bit) floating-point elements from
+// the high half of a and b, and store the results in dst.
+//
+//   DEFINE INTERLEAVE_HIGH_QWORDS(src1[127:0], src2[127:0]) {
+//     dst[63:0] := src1[127:64]
+//     dst[127:64] := src2[127:64]
+//     RETURN dst[127:0]
+//   }
+//   dst[127:0] := INTERLEAVE_HIGH_QWORDS(a[127:0], b[127:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpackhi_pd
+FORCE_INLINE __m128d _mm_unpackhi_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128d_f64(
+        vzip2q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+    return vreinterpretq_m128d_s64(
+        vcombine_s64(vget_high_s64(vreinterpretq_s64_m128d(a)),
+                     vget_high_s64(vreinterpretq_s64_m128d(b))));
+#endif
+}
+
+// Selects and interleaves the upper two single-precision, floating-point values
+// from a and b.
+//
+//   r0 := a2
+//   r1 := b2
+//   r2 := a3
+//   r3 := b3
+//
+// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128_f32(
+        vzip2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+    float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a));
+    float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b));
+    float32x2x2_t result = vzip_f32(a1, b1);
+    return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper
+// 8 signed or unsigned 8-bit integers in b.
+//
+//   r0 := a8
+//   r1 := b8
+//   r2 := a9
+//   r3 := b9
+//   ...
+//   r14 := a15
+//   r15 := b15
+//
+// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s8(
+        vzip2q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+#else
+    int8x8_t a1 =
+        vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a)));
+    int8x8_t b1 =
+        vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b)));
+    int8x8x2_t result = vzip_s8(a1, b1);
+    return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the
+// upper 4 signed or unsigned 16-bit integers in b.
+//
+//   r0 := a4
+//   r1 := b4
+//   r2 := a5
+//   r3 := b5
+//   r4 := a6
+//   r5 := b6
+//   r6 := a7
+//   r7 := b7
+//
+// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s16(
+        vzip2q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+#else
+    int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a));
+    int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b));
+    int16x4x2_t result = vzip_s16(a1, b1);
+    return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the
+// upper 2 signed or unsigned 32-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+    return vreinterpretq_m128i_s32(
+        vzip2q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+#else
+    int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a));
+    int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b));
+    int32x2x2_t result = vzip_s32(a1, b1);
+    return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper signed or unsigned 64-bit integer in a with the
+// upper signed or unsigned 64-bit integer in b.
+//
+//   r0 := a1
+//   r1 := b1
+FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)
+{
+    int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a));
+    int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b));
+    return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h));
+}
+
+// Horizontally compute the minimum amongst the packed unsigned 16-bit integers
+// in a, store the minimum and index in dst, and zero the remaining bits in dst.
+//
+//   index[2:0] := 0
+//   min[15:0] := a[15:0]
+//   FOR j := 0 to 7
+//       i := j*16
+//       IF a[i+15:i] < min[15:0]
+//           index[2:0] := j
+//           min[15:0] := a[i+15:i]
+//       FI
+//   ENDFOR
+//   dst[15:0] := min[15:0]
+//   dst[18:16] := index[2:0]
+//   dst[127:19] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_minpos_epu16
+FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a)
+{
+    __m128i dst;
+    uint16_t min, idx = 0;
+    // Find the minimum value
+#if defined(__aarch64__)
+    min = vminvq_u16(vreinterpretq_u16_m128i(a));
+#else
+    __m64 tmp;
+    tmp = vreinterpret_m64_u16(
+        vmin_u16(vget_low_u16(vreinterpretq_u16_m128i(a)),
+                 vget_high_u16(vreinterpretq_u16_m128i(a))));
+    tmp = vreinterpret_m64_u16(
+        vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp)));
+    tmp = vreinterpret_m64_u16(
+        vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp)));
+    min = vget_lane_u16(vreinterpret_u16_m64(tmp), 0);
+#endif
+    // Get the index of the minimum value
+    int i;
+    for (i = 0; i < 8; i++) {
+        if (min == vgetq_lane_u16(vreinterpretq_u16_m128i(a), 0)) {
+            idx = (uint16_t) i;
+            break;
+        }
+        a = _mm_srli_si128(a, 2);
+    }
+    // Generate result
+    dst = _mm_setzero_si128();
+    dst = vreinterpretq_m128i_u16(
+        vsetq_lane_u16(min, vreinterpretq_u16_m128i(dst), 0));
+    dst = vreinterpretq_m128i_u16(
+        vsetq_lane_u16(idx, vreinterpretq_u16_m128i(dst), 1));
+    return dst;
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and b,
+// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the
+// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero,
+// otherwise set CF to 0. Return the CF value.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testc_si128
+FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b)
+{
+    int64x2_t s64 =
+        vandq_s64(vreinterpretq_s64_s32(vmvnq_s32(vreinterpretq_s32_m128i(a))),
+                  vreinterpretq_s64_m128i(b));
+    return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1));
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and b,
+// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the
+// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero,
+// otherwise set CF to 0. Return the ZF value.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testz_si128
+FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b)
+{
+    int64x2_t s64 =
+        vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b));
+    return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1));
+}
+
+// Extracts the selected signed or unsigned 8-bit integer from a and zero
+// extends.
+// FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm)
+#define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm))
+
+// Inserts the least significant 8 bits of b into the selected 8-bit integer
+// of a.
+// FORCE_INLINE __m128i _mm_insert_epi8(__m128i a, int b,
+//                                      __constrange(0,16) int imm)
+#define _mm_insert_epi8(a, b, imm)                                 \
+    __extension__({                                                \
+        vreinterpretq_m128i_s8(                                    \
+            vsetq_lane_s8((b), vreinterpretq_s8_m128i(a), (imm))); \
+    })
+
+// Extracts the selected signed or unsigned 16-bit integer from a and zero
+// extends.
+// https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx
+// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm)
+#define _mm_extract_epi16(a, imm) \
+    vgetq_lane_u16(vreinterpretq_u16_m128i(a), (imm))
+
+// Inserts the least significant 16 bits of b into the selected 16-bit integer
+// of a.
+// https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx
+// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, int b,
+//                                       __constrange(0,8) int imm)
+#define _mm_insert_epi16(a, b, imm)                                  \
+    __extension__({                                                  \
+        vreinterpretq_m128i_s16(                                     \
+            vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \
+    })
+
+// Copy a to dst, and insert the 16-bit integer i into dst at the location
+// specified by imm8.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_insert_pi16
+#define _mm_insert_pi16(a, b, imm)                               \
+    __extension__({                                              \
+        vreinterpret_m64_s16(                                    \
+            vset_lane_s16((b), vreinterpret_s16_m64(a), (imm))); \
+    })
+
+// Extracts the selected signed or unsigned 32-bit integer from a and zero
+// extends.
+// FORCE_INLINE int _mm_extract_epi32(__m128i a, __constrange(0,4) int imm)
+#define _mm_extract_epi32(a, imm) \
+    vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm))
+
+// Extracts the selected single-precision (32-bit) floating-point from a.
+// FORCE_INLINE int _mm_extract_ps(__m128 a, __constrange(0,4) int imm)
+#define _mm_extract_ps(a, imm) vgetq_lane_s32(vreinterpretq_s32_m128(a), (imm))
+
+// Inserts the least significant 32 bits of b into the selected 32-bit integer
+// of a.
+// FORCE_INLINE __m128i _mm_insert_epi32(__m128i a, int b,
+//                                       __constrange(0,4) int imm)
+#define _mm_insert_epi32(a, b, imm)                                  \
+    __extension__({                                                  \
+        vreinterpretq_m128i_s32(                                     \
+            vsetq_lane_s32((b), vreinterpretq_s32_m128i(a), (imm))); \
+    })
+
+// Extracts the selected signed or unsigned 64-bit integer from a and zero
+// extends.
+// FORCE_INLINE __int64 _mm_extract_epi64(__m128i a, __constrange(0,2) int imm)
+#define _mm_extract_epi64(a, imm) \
+    vgetq_lane_s64(vreinterpretq_s64_m128i(a), (imm))
+
+// Inserts the least significant 64 bits of b into the selected 64-bit integer
+// of a.
+// FORCE_INLINE __m128i _mm_insert_epi64(__m128i a, __int64 b,
+//                                       __constrange(0,2) int imm)
+#define _mm_insert_epi64(a, b, imm)                                  \
+    __extension__({                                                  \
+        vreinterpretq_m128i_s64(                                     \
+            vsetq_lane_s64((b), vreinterpretq_s64_m128i(a), (imm))); \
+    })
+
+// Count the number of bits set to 1 in unsigned 32-bit integer a, and
+// return that count in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32
+FORCE_INLINE int _mm_popcnt_u32(unsigned int a)
+{
+#if defined(__aarch64__)
+#if __has_builtin(__builtin_popcount)
+    return __builtin_popcount(a);
+#else
+    return (int) vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t) a)));
+#endif
+#else
+    uint32_t count = 0;
+    uint8x8_t input_val, count8x8_val;
+    uint16x4_t count16x4_val;
+    uint32x2_t count32x2_val;
+
+    input_val = vld1_u8((uint8_t *) &a);
+    count8x8_val = vcnt_u8(input_val);
+    count16x4_val = vpaddl_u8(count8x8_val);
+    count32x2_val = vpaddl_u16(count16x4_val);
+
+    vst1_u32(&count, count32x2_val);
+    return count;
+#endif
+}
+
+// Count the number of bits set to 1 in unsigned 64-bit integer a, and
+// return that count in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64
+FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a)
+{
+#if defined(__aarch64__)
+#if __has_builtin(__builtin_popcountll)
+    return __builtin_popcountll(a);
+#else
+    return (int64_t) vaddlv_u8(vcnt_u8(vcreate_u8(a)));
+#endif
+#else
+    uint64_t count = 0;
+    uint8x8_t input_val, count8x8_val;
+    uint16x4_t count16x4_val;
+    uint32x2_t count32x2_val;
+    uint64x1_t count64x1_val;
+
+    input_val = vld1_u8((uint8_t *) &a);
+    count8x8_val = vcnt_u8(input_val);
+    count16x4_val = vpaddl_u8(count8x8_val);
+    count32x2_val = vpaddl_u16(count16x4_val);
+    count64x1_val = vpaddl_u32(count32x2_val);
+    vst1_u64(&count, count64x1_val);
+    return count;
+#endif
+}
+
+// Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision
+// (32-bit) floating-point elements in row0, row1, row2, and row3, and store the
+// transposed matrix in these vectors (row0 now contains column 0, etc.).
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS
+#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3)         \
+    do {                                                  \
+        float32x4x2_t ROW01 = vtrnq_f32(row0, row1);      \
+        float32x4x2_t ROW23 = vtrnq_f32(row2, row3);      \
+        row0 = vcombine_f32(vget_low_f32(ROW01.val[0]),   \
+                            vget_low_f32(ROW23.val[0]));  \
+        row1 = vcombine_f32(vget_low_f32(ROW01.val[1]),   \
+                            vget_low_f32(ROW23.val[1]));  \
+        row2 = vcombine_f32(vget_high_f32(ROW01.val[0]),  \
+                            vget_high_f32(ROW23.val[0])); \
+        row3 = vcombine_f32(vget_high_f32(ROW01.val[1]),  \
+                            vget_high_f32(ROW23.val[1])); \
+    } while (0)
+
+/* Crypto Extensions */
+
+#if defined(__ARM_FEATURE_CRYPTO)
+// Wraps vmull_p64
+FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b)
+{
+    poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0);
+    poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0);
+    return vreinterpretq_u64_p128(vmull_p64(a, b));
+}
+#else  // ARMv7 polyfill
+// ARMv7/some A64 lacks vmull_p64, but it has vmull_p8.
+//
+// vmull_p8 calculates 8 8-bit->16-bit polynomial multiplies, but we need a
+// 64-bit->128-bit polynomial multiply.
+//
+// It needs some work and is somewhat slow, but it is still faster than all
+// known scalar methods.
+//
+// Algorithm adapted to C from
+// https://www.workofard.com/2017/07/ghash-for-low-end-cores/, which is adapted
+// from "Fast Software Polynomial Multiplication on ARM Processors Using the
+// NEON Engine" by Danilo Camara, Conrado Gouvea, Julio Lopez and Ricardo Dahab
+// (https://hal.inria.fr/hal-01506572)
+static uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b)
+{
+    poly8x8_t a = vreinterpret_p8_u64(_a);
+    poly8x8_t b = vreinterpret_p8_u64(_b);
+
+    // Masks
+    uint8x16_t k48_32 = vcombine_u8(vcreate_u8(0x0000ffffffffffff),
+                                    vcreate_u8(0x00000000ffffffff));
+    uint8x16_t k16_00 = vcombine_u8(vcreate_u8(0x000000000000ffff),
+                                    vcreate_u8(0x0000000000000000));
+
+    // Do the multiplies, rotating with vext to get all combinations
+    uint8x16_t d = vreinterpretq_u8_p16(vmull_p8(a, b));  // D = A0 * B0
+    uint8x16_t e =
+        vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 1)));  // E = A0 * B1
+    uint8x16_t f =
+        vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 1), b));  // F = A1 * B0
+    uint8x16_t g =
+        vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 2)));  // G = A0 * B2
+    uint8x16_t h =
+        vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 2), b));  // H = A2 * B0
+    uint8x16_t i =
+        vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 3)));  // I = A0 * B3
+    uint8x16_t j =
+        vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 3), b));  // J = A3 * B0
+    uint8x16_t k =
+        vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 4)));  // L = A0 * B4
+
+    // Add cross products
+    uint8x16_t l = veorq_u8(e, f);  // L = E + F
+    uint8x16_t m = veorq_u8(g, h);  // M = G + H
+    uint8x16_t n = veorq_u8(i, j);  // N = I + J
+
+    // Interleave. Using vzip1 and vzip2 prevents Clang from emitting TBL
+    // instructions.
+#if defined(__aarch64__)
+    uint8x16_t lm_p0 = vreinterpretq_u8_u64(
+        vzip1q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m)));
+    uint8x16_t lm_p1 = vreinterpretq_u8_u64(
+        vzip2q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m)));
+    uint8x16_t nk_p0 = vreinterpretq_u8_u64(
+        vzip1q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k)));
+    uint8x16_t nk_p1 = vreinterpretq_u8_u64(
+        vzip2q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k)));
+#else
+    uint8x16_t lm_p0 = vcombine_u8(vget_low_u8(l), vget_low_u8(m));
+    uint8x16_t lm_p1 = vcombine_u8(vget_high_u8(l), vget_high_u8(m));
+    uint8x16_t nk_p0 = vcombine_u8(vget_low_u8(n), vget_low_u8(k));
+    uint8x16_t nk_p1 = vcombine_u8(vget_high_u8(n), vget_high_u8(k));
+#endif
+    // t0 = (L) (P0 + P1) << 8
+    // t1 = (M) (P2 + P3) << 16
+    uint8x16_t t0t1_tmp = veorq_u8(lm_p0, lm_p1);
+    uint8x16_t t0t1_h = vandq_u8(lm_p1, k48_32);
+    uint8x16_t t0t1_l = veorq_u8(t0t1_tmp, t0t1_h);
+
+    // t2 = (N) (P4 + P5) << 24
+    // t3 = (K) (P6 + P7) << 32
+    uint8x16_t t2t3_tmp = veorq_u8(nk_p0, nk_p1);
+    uint8x16_t t2t3_h = vandq_u8(nk_p1, k16_00);
+    uint8x16_t t2t3_l = veorq_u8(t2t3_tmp, t2t3_h);
+
+    // De-interleave
+#if defined(__aarch64__)
+    uint8x16_t t0 = vreinterpretq_u8_u64(
+        vuzp1q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h)));
+    uint8x16_t t1 = vreinterpretq_u8_u64(
+        vuzp2q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h)));
+    uint8x16_t t2 = vreinterpretq_u8_u64(
+        vuzp1q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h)));
+    uint8x16_t t3 = vreinterpretq_u8_u64(
+        vuzp2q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h)));
+#else
+    uint8x16_t t1 = vcombine_u8(vget_high_u8(t0t1_l), vget_high_u8(t0t1_h));
+    uint8x16_t t0 = vcombine_u8(vget_low_u8(t0t1_l), vget_low_u8(t0t1_h));
+    uint8x16_t t3 = vcombine_u8(vget_high_u8(t2t3_l), vget_high_u8(t2t3_h));
+    uint8x16_t t2 = vcombine_u8(vget_low_u8(t2t3_l), vget_low_u8(t2t3_h));
+#endif
+    // Shift the cross products
+    uint8x16_t t0_shift = vextq_u8(t0, t0, 15);  // t0 << 8
+    uint8x16_t t1_shift = vextq_u8(t1, t1, 14);  // t1 << 16
+    uint8x16_t t2_shift = vextq_u8(t2, t2, 13);  // t2 << 24
+    uint8x16_t t3_shift = vextq_u8(t3, t3, 12);  // t3 << 32
+
+    // Accumulate the products
+    uint8x16_t cross1 = veorq_u8(t0_shift, t1_shift);
+    uint8x16_t cross2 = veorq_u8(t2_shift, t3_shift);
+    uint8x16_t mix = veorq_u8(d, cross1);
+    uint8x16_t r = veorq_u8(mix, cross2);
+    return vreinterpretq_u64_u8(r);
+}
+#endif  // ARMv7 polyfill
+
+// Perform a carry-less multiplication of two 64-bit integers, selected from a
+// and b according to imm8, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_clmulepi64_si128
+FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm)
+{
+    uint64x2_t a = vreinterpretq_u64_m128i(_a);
+    uint64x2_t b = vreinterpretq_u64_m128i(_b);
+    switch (imm & 0x11) {
+    case 0x00:
+        return vreinterpretq_m128i_u64(
+            _sse2neon_vmull_p64(vget_low_u64(a), vget_low_u64(b)));
+    case 0x01:
+        return vreinterpretq_m128i_u64(
+            _sse2neon_vmull_p64(vget_high_u64(a), vget_low_u64(b)));
+    case 0x10:
+        return vreinterpretq_m128i_u64(
+            _sse2neon_vmull_p64(vget_low_u64(a), vget_high_u64(b)));
+    case 0x11:
+        return vreinterpretq_m128i_u64(
+            _sse2neon_vmull_p64(vget_high_u64(a), vget_high_u64(b)));
+    default:
+        abort();
+    }
+}
+
+#if !defined(__ARM_FEATURE_CRYPTO)
+/* clang-format off */
+#define SSE2NEON_AES_DATA(w)                                           \
+    {                                                                  \
+        w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), \
+        w(0xc5), w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), \
+        w(0xab), w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), \
+        w(0x59), w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), \
+        w(0x9c), w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), \
+        w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), \
+        w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), \
+        w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), \
+        w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), \
+        w(0x75), w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), \
+        w(0x5a), w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), \
+        w(0xe3), w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), \
+        w(0x20), w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), \
+        w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), \
+        w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), \
+        w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), \
+        w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), \
+        w(0xf5), w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), \
+        w(0xf3), w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), \
+        w(0x97), w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), \
+        w(0x64), w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), \
+        w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), \
+        w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), \
+        w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), \
+        w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), \
+        w(0x79), w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), \
+        w(0x4e), w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), \
+        w(0x7a), w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), \
+        w(0x1c), w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), \
+        w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), \
+        w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), \
+        w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), \
+        w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), \
+        w(0x94), w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), \
+        w(0x28), w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), \
+        w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), \
+        w(0xb0), w(0x54), w(0xbb), w(0x16)                             \
+    }
+/* clang-format on */
+
+/* X Macro trick. See https://en.wikipedia.org/wiki/X_Macro */
+#define SSE2NEON_AES_H0(x) (x)
+static const uint8_t SSE2NEON_sbox[256] = SSE2NEON_AES_DATA(SSE2NEON_AES_H0);
+#undef SSE2NEON_AES_H0
+
+// In the absence of crypto extensions, implement aesenc using regular neon
+// intrinsics instead. See:
+// https://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/
+// https://www.workofard.com/2017/07/ghash-for-low-end-cores/ and
+// https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52
+// for more information Reproduced with permission of the author.
+FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey)
+{
+#if defined(__aarch64__)
+    static const uint8_t shift_rows[] = {0x0, 0x5, 0xa, 0xf, 0x4, 0x9,
+                                         0xe, 0x3, 0x8, 0xd, 0x2, 0x7,
+                                         0xc, 0x1, 0x6, 0xb};
+    static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4,
+                                       0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc};
+
+    uint8x16_t v;
+    uint8x16_t w = vreinterpretq_u8_m128i(EncBlock);
+
+    // shift rows
+    w = vqtbl1q_u8(w, vld1q_u8(shift_rows));
+
+    // sub bytes
+    v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(SSE2NEON_sbox), w);
+    v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x40), w - 0x40);
+    v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x80), w - 0x80);
+    v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0xc0), w - 0xc0);
+
+    // mix columns
+    w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b);
+    w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v);
+    w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8));
+
+    //  add round key
+    return vreinterpretq_m128i_u8(w) ^ RoundKey;
+
+#else /* ARMv7-A NEON implementation */
+#define SSE2NEON_AES_B2W(b0, b1, b2, b3)                                       \
+    (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | \
+     (b0))
+#define SSE2NEON_AES_F2(x) ((x << 1) ^ (((x >> 7) & 1) * 0x011b /* WPOLY */))
+#define SSE2NEON_AES_F3(x) (SSE2NEON_AES_F2(x) ^ x)
+#define SSE2NEON_AES_U0(p) \
+    SSE2NEON_AES_B2W(SSE2NEON_AES_F2(p), p, p, SSE2NEON_AES_F3(p))
+#define SSE2NEON_AES_U1(p) \
+    SSE2NEON_AES_B2W(SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p, p)
+#define SSE2NEON_AES_U2(p) \
+    SSE2NEON_AES_B2W(p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p)
+#define SSE2NEON_AES_U3(p) \
+    SSE2NEON_AES_B2W(p, p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p))
+    static const uint32_t ALIGN_STRUCT(16) aes_table[4][256] = {
+        SSE2NEON_AES_DATA(SSE2NEON_AES_U0),
+        SSE2NEON_AES_DATA(SSE2NEON_AES_U1),
+        SSE2NEON_AES_DATA(SSE2NEON_AES_U2),
+        SSE2NEON_AES_DATA(SSE2NEON_AES_U3),
+    };
+#undef SSE2NEON_AES_B2W
+#undef SSE2NEON_AES_F2
+#undef SSE2NEON_AES_F3
+#undef SSE2NEON_AES_U0
+#undef SSE2NEON_AES_U1
+#undef SSE2NEON_AES_U2
+#undef SSE2NEON_AES_U3
+
+    uint32_t x0 = _mm_cvtsi128_si32(EncBlock);
+    uint32_t x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0x55));
+    uint32_t x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xAA));
+    uint32_t x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xFF));
+
+    __m128i out = _mm_set_epi32(
+        (aes_table[0][x3 & 0xff] ^ aes_table[1][(x0 >> 8) & 0xff] ^
+         aes_table[2][(x1 >> 16) & 0xff] ^ aes_table[3][x2 >> 24]),
+        (aes_table[0][x2 & 0xff] ^ aes_table[1][(x3 >> 8) & 0xff] ^
+         aes_table[2][(x0 >> 16) & 0xff] ^ aes_table[3][x1 >> 24]),
+        (aes_table[0][x1 & 0xff] ^ aes_table[1][(x2 >> 8) & 0xff] ^
+         aes_table[2][(x3 >> 16) & 0xff] ^ aes_table[3][x0 >> 24]),
+        (aes_table[0][x0 & 0xff] ^ aes_table[1][(x1 >> 8) & 0xff] ^
+         aes_table[2][(x2 >> 16) & 0xff] ^ aes_table[3][x3 >> 24]));
+
+    return _mm_xor_si128(out, RoundKey);
+#endif
+}
+
+// Perform the last round of an AES encryption flow on data (state) in a using
+// the round key in RoundKey, and store the result in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128
+FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey)
+{
+    /* FIXME: optimized for NEON */
+    uint8_t v[4][4] = {
+        [0] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]},
+        [1] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]},
+        [2] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]},
+        [3] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)],
+               SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]},
+    };
+    for (int i = 0; i < 16; i++)
+        vreinterpretq_nth_u8_m128i(a, i) =
+            v[i / 4][i % 4] ^ vreinterpretq_nth_u8_m128i(RoundKey, i);
+    return a;
+}
+
+// Emits the Advanced Encryption Standard (AES) instruction aeskeygenassist.
+// This instruction generates a round key for AES encryption. See
+// https://kazakov.life/2017/11/01/cryptocurrency-mining-on-ios-devices/
+// for details.
+//
+// https://msdn.microsoft.com/en-us/library/cc714138(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i key, const int rcon)
+{
+    uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55));
+    uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF));
+    for (int i = 0; i < 4; ++i) {
+        ((uint8_t *) &X1)[i] = SSE2NEON_sbox[((uint8_t *) &X1)[i]];
+        ((uint8_t *) &X3)[i] = SSE2NEON_sbox[((uint8_t *) &X3)[i]];
+    }
+    return _mm_set_epi32(((X3 >> 8) | (X3 << 24)) ^ rcon, X3,
+                         ((X1 >> 8) | (X1 << 24)) ^ rcon, X1);
+}
+#undef SSE2NEON_AES_DATA
+
+#else /* __ARM_FEATURE_CRYPTO */
+// Implements equivalent of 'aesenc' by combining AESE (with an empty key) and
+// AESMC and then manually applying the real key as an xor operation. This
+// unfortunately means an additional xor op; the compiler should be able to
+// optimize this away for repeated calls however. See
+// https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a
+// for more details.
+FORCE_INLINE __m128i _mm_aesenc_si128(__m128i a, __m128i b)
+{
+    return vreinterpretq_m128i_u8(
+        vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0))) ^
+        vreinterpretq_u8_m128i(b));
+}
+
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128
+FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey)
+{
+    return _mm_xor_si128(vreinterpretq_m128i_u8(vaeseq_u8(
+                             vreinterpretq_u8_m128i(a), vdupq_n_u8(0))),
+                         RoundKey);
+}
+
+FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon)
+{
+    // AESE does ShiftRows and SubBytes on A
+    uint8x16_t u8 = vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0));
+
+    uint8x16_t dest = {
+        // Undo ShiftRows step from AESE and extract X1 and X3
+        u8[0x4], u8[0x1], u8[0xE], u8[0xB],  // SubBytes(X1)
+        u8[0x1], u8[0xE], u8[0xB], u8[0x4],  // ROT(SubBytes(X1))
+        u8[0xC], u8[0x9], u8[0x6], u8[0x3],  // SubBytes(X3)
+        u8[0x9], u8[0x6], u8[0x3], u8[0xC],  // ROT(SubBytes(X3))
+    };
+    uint32x4_t r = {0, (unsigned) rcon, 0, (unsigned) rcon};
+    return vreinterpretq_m128i_u8(dest) ^ vreinterpretq_m128i_u32(r);
+}
+#endif
+
+/* Streaming Extensions */
+
+// Guarantees that every preceding store is globally visible before any
+// subsequent store.
+// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_sfence(void)
+{
+    __sync_synchronize();
+}
+
+// Store 128-bits (composed of 4 packed single-precision (32-bit) floating-
+// point elements) from a into memory using a non-temporal memory hint.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps
+FORCE_INLINE void _mm_stream_ps(float *p, __m128 a)
+{
+#if __has_builtin(__builtin_nontemporal_store)
+    __builtin_nontemporal_store(a, (float32x4_t *) p);
+#else
+    vst1q_f32(p, vreinterpretq_f32_m128(a));
+#endif
+}
+
+// Stores the data in a to the address p without polluting the caches.  If the
+// cache line containing address p is already in the cache, the cache will be
+// updated.
+// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a)
+{
+#if __has_builtin(__builtin_nontemporal_store)
+    __builtin_nontemporal_store(a, p);
+#else
+    vst1q_s64((int64_t *) p, vreinterpretq_s64_m128i(a));
+#endif
+}
+
+// Load 128-bits of integer data from memory into dst using a non-temporal
+// memory hint. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+//   dst[127:0] := MEM[mem_addr+127:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128
+FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p)
+{
+#if __has_builtin(__builtin_nontemporal_store)
+    return __builtin_nontemporal_load(p);
+#else
+    return vreinterpretq_m128i_s64(vld1q_s64((int64_t *) p));
+#endif
+}
+
+// Cache line containing p is flushed and invalidated from all caches in the
+// coherency domain. :
+// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx
+FORCE_INLINE void _mm_clflush(void const *p)
+{
+    (void) p;
+    // no corollary for Neon?
+}
+
+// Allocate aligned blocks of memory.
+// https://software.intel.com/en-us/
+//         cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks
+FORCE_INLINE void *_mm_malloc(size_t size, size_t align)
+{
+    void *ptr;
+    if (align == 1)
+        return malloc(size);
+    if (align == 2 || (sizeof(void *) == 8 && align == 4))
+        align = sizeof(void *);
+    if (!posix_memalign(&ptr, align, size))
+        return ptr;
+    return NULL;
+}
+
+// Free aligned memory that was allocated with _mm_malloc.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_free
+FORCE_INLINE void _mm_free(void *addr)
+{
+    free(addr);
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 8-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb514036(v=vs.100)
+FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+    __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t"
+                         : [c] "+r"(crc)
+                         : [v] "r"(v));
+#else
+    crc ^= v;
+    for (int bit = 0; bit < 8; bit++) {
+        if (crc & 1)
+            crc = (crc >> 1) ^ UINT32_C(0x82f63b78);
+        else
+            crc = (crc >> 1);
+    }
+#endif
+    return crc;
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 16-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb531411(v=vs.100)
+FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+    __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t"
+                         : [c] "+r"(crc)
+                         : [v] "r"(v));
+#else
+    crc = _mm_crc32_u8(crc, v & 0xff);
+    crc = _mm_crc32_u8(crc, (v >> 8) & 0xff);
+#endif
+    return crc;
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 32-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb531394(v=vs.100)
+FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+    __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t"
+                         : [c] "+r"(crc)
+                         : [v] "r"(v));
+#else
+    crc = _mm_crc32_u16(crc, v & 0xffff);
+    crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff);
+#endif
+    return crc;
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 64-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb514033(v=vs.100)
+FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+    __asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t"
+                         : [c] "+r"(crc)
+                         : [v] "r"(v));
+#else
+    crc = _mm_crc32_u32((uint32_t)(crc), v & 0xffffffff);
+    crc = _mm_crc32_u32((uint32_t)(crc), (v >> 32) & 0xffffffff);
+#endif
+    return crc;
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma pop_macro("ALIGN_STRUCT")
+#pragma pop_macro("FORCE_INLINE")
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC pop_options
+#endif
+
+#endif

+ 1 - 1
thirdparty/embree-aarch64/common/simd/avx.h → thirdparty/embree/common/simd/avx.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 1 - 1
thirdparty/embree-aarch64/common/simd/avx512.h → thirdparty/embree/common/simd/avx512.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once

+ 2 - 2
thirdparty/embree-aarch64/common/simd/simd.h → thirdparty/embree/common/simd/simd.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -6,7 +6,7 @@
 #include "../math/math.h"
 #include "../math/math.h"
 
 
 /* include SSE wrapper classes */
 /* include SSE wrapper classes */
-#if defined(__SSE__) || defined(__ARM_NEON)
+#if defined(__SSE__)
 #  include "sse.h"
 #  include "sse.h"
 #endif
 #endif
 
 

+ 1 - 1
thirdparty/embree-aarch64/common/simd/sse.cpp → thirdparty/embree/common/simd/sse.cpp

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #include "sse.h"
 #include "sse.h"

+ 2 - 2
thirdparty/embree-aarch64/common/simd/sse.h → thirdparty/embree/common/simd/sse.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -11,7 +11,7 @@
 
 
 namespace embree 
 namespace embree 
 {
 {
-#if (defined(__aarch64__) && defined(BUILD_IOS)) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline __m128 blendv_ps(__m128 f, __m128 t, __m128 mask) { 
   __forceinline __m128 blendv_ps(__m128 f, __m128 t, __m128 mask) { 
     return _mm_blendv_ps(f,t,mask);
     return _mm_blendv_ps(f,t,mask);
   }
   }

+ 42 - 29
thirdparty/embree-aarch64/common/simd/varying.h → thirdparty/embree/common/simd/varying.h

@@ -1,4 +1,4 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
@@ -9,7 +9,7 @@ namespace embree
 {
 {
   /* Varying numeric types */
   /* Varying numeric types */
   template<int N>
   template<int N>
-  struct vfloat
+  struct vfloat_impl
   {
   {
     union { float f[N]; int i[N]; };
     union { float f[N]; int i[N]; };
     __forceinline const float& operator [](size_t index) const { assert(index < N); return f[index]; }
     __forceinline const float& operator [](size_t index) const { assert(index < N); return f[index]; }
@@ -17,7 +17,7 @@ namespace embree
   };
   };
 
 
   template<int N>
   template<int N>
-  struct vdouble
+  struct vdouble_impl
   {
   {
     union { double f[N]; long long i[N]; };
     union { double f[N]; long long i[N]; };
     __forceinline const double& operator [](size_t index) const { assert(index < N); return f[index]; }
     __forceinline const double& operator [](size_t index) const { assert(index < N); return f[index]; }
@@ -25,7 +25,7 @@ namespace embree
   };
   };
 
 
   template<int N>
   template<int N>
-  struct vint
+  struct vint_impl
   {
   {
     int i[N];
     int i[N];
     __forceinline const int& operator [](size_t index) const { assert(index < N); return i[index]; }
     __forceinline const int& operator [](size_t index) const { assert(index < N); return i[index]; }
@@ -33,7 +33,7 @@ namespace embree
   };
   };
 
 
   template<int N>
   template<int N>
-  struct vuint
+  struct vuint_impl
   {
   {
     unsigned int i[N];
     unsigned int i[N];
     __forceinline const unsigned int& operator [](size_t index) const { assert(index < N); return i[index]; }
     __forceinline const unsigned int& operator [](size_t index) const { assert(index < N); return i[index]; }
@@ -41,7 +41,7 @@ namespace embree
   };
   };
 
 
   template<int N>
   template<int N>
-  struct vllong
+  struct vllong_impl
   {
   {
     long long i[N];
     long long i[N];
     __forceinline const long long& operator [](size_t index) const { assert(index < N); return i[index]; }
     __forceinline const long long& operator [](size_t index) const { assert(index < N); return i[index]; }
@@ -49,20 +49,13 @@ namespace embree
   };
   };
 
 
   /* Varying bool types */
   /* Varying bool types */
-  template<int N> struct vboolf { int       i[N]; }; // for float/int
-  template<int N> struct vboold { long long i[N]; }; // for double/long long
-
-  /* Aliases to default types */
-  template<int N> using vreal = vfloat<N>;
-  template<int N> using vbool = vboolf<N>;
-
+  template<int N> struct vboolf_impl { int       i[N]; }; // for float/int
+  template<int N> struct vboold_impl { long long i[N]; }; // for double/long long
+ 
   /* Varying size constants */
   /* Varying size constants */
 #if defined(__AVX512VL__) // SKX
 #if defined(__AVX512VL__) // SKX
   const int VSIZEX = 8;  // default size
   const int VSIZEX = 8;  // default size
   const int VSIZEL = 16; // large size
   const int VSIZEL = 16; // large size
-#elif defined(__AVX512F__) // KNL
-  const int VSIZEX = 16;
-  const int VSIZEL = 16;
 #elif defined(__AVX__)
 #elif defined(__AVX__)
   const int VSIZEX = 8;
   const int VSIZEX = 8;
   const int VSIZEL = 8;
   const int VSIZEL = 8;
@@ -71,21 +64,41 @@ namespace embree
   const int VSIZEL = 4;
   const int VSIZEL = 4;
 #endif
 #endif
 
 
-  /* Extends varying size N to optimal or up to max(N, N2) */
-  template<int N, int N2 = VSIZEX>
-  struct vextend
-  {
-#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
-    /* use 16-wide SIMD calculations on KNL even for 4 and 8 wide SIMD */
-    static const int size = (N2 == VSIZEX) ? VSIZEX : N;
-    #define SIMD_MODE(N) N, 16
-#else
-    /* calculate with same SIMD width otherwise */
-    static const int size = N;
-    #define SIMD_MODE(N) N, N
-#endif
+  template<int N>
+  struct vtypes {
+    using vbool = vboolf_impl<N>;
+    using vboolf = vboolf_impl<N>;
+    using vboold = vboold_impl<N>;
+    using vint = vint_impl<N>;
+    using vuint = vuint_impl<N>;
+    using vllong = vllong_impl<N>;
+    using vfloat = vfloat_impl<N>;
+    using vdouble = vdouble_impl<N>;
+  };
+
+  template<>
+  struct vtypes<1> {
+    using vbool = bool;
+    using vboolf = bool;
+    using vboold = bool;
+    using vint = int;
+    using vuint = unsigned int;
+    using vllong = long long;
+    using vfloat = float;
+    using vdouble = double;
   };
   };
 
 
+  /* Aliases to default types */
+  template<int N> using vbool = typename vtypes<N>::vbool;
+  template<int N> using vboolf = typename vtypes<N>::vboolf;
+  template<int N> using vboold = typename vtypes<N>::vboold;
+  template<int N> using vint = typename vtypes<N>::vint;
+  template<int N> using vuint = typename vtypes<N>::vuint;
+  template<int N> using vllong = typename vtypes<N>::vllong;
+  template<int N> using vreal = typename vtypes<N>::vfloat;
+  template<int N> using vfloat = typename vtypes<N>::vfloat;
+  template<int N> using vdouble = typename vtypes<N>::vdouble;
+
   /* 4-wide shortcuts */
   /* 4-wide shortcuts */
   typedef vfloat<4>  vfloat4;
   typedef vfloat<4>  vfloat4;
   typedef vdouble<4> vdouble4;
   typedef vdouble<4> vdouble4;

+ 19 - 10
thirdparty/embree-aarch64/common/simd/vboold4_avx.h → thirdparty/embree/common/simd/vboold4_avx.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide AVX bool type for 64bit data types*/
   /* 4-wide AVX bool type for 64bit data types*/
@@ -49,19 +57,13 @@ namespace embree
 #endif
 #endif
     }
     }
     
     
-    __forceinline vboold(__m128d a, __m128d b) : vl(a), vh(b) {}
-
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Constants
     /// Constants
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
 
 
     __forceinline vboold(FalseTy) : v(_mm256_setzero_pd()) {}
     __forceinline vboold(FalseTy) : v(_mm256_setzero_pd()) {}
-#if !defined(__aarch64__)
     __forceinline vboold(TrueTy)  : v(_mm256_cmp_pd(_mm256_setzero_pd(), _mm256_setzero_pd(), _CMP_EQ_OQ)) {}
     __forceinline vboold(TrueTy)  : v(_mm256_cmp_pd(_mm256_setzero_pd(), _mm256_setzero_pd(), _CMP_EQ_OQ)) {}
-#else
-    __forceinline vboold(TrueTy)  : v(_mm256_cmpeq_pd(_mm256_setzero_pd(), _mm256_setzero_pd())) {}
-#endif
-      
+
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -105,10 +107,9 @@ namespace embree
   /// Movement/Shifting/Shuffling Functions
   /// Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if !defined(__aarch64__)
   __forceinline vboold4 unpacklo(const vboold4& a, const vboold4& b) { return _mm256_unpacklo_pd(a, b); }
   __forceinline vboold4 unpacklo(const vboold4& a, const vboold4& b) { return _mm256_unpacklo_pd(a, b); }
   __forceinline vboold4 unpackhi(const vboold4& a, const vboold4& b) { return _mm256_unpackhi_pd(a, b); }
   __forceinline vboold4 unpackhi(const vboold4& a, const vboold4& b) { return _mm256_unpackhi_pd(a, b); }
-#endif
+
 
 
 #if defined(__AVX2__)
 #if defined(__AVX2__)
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
@@ -158,3 +159,11 @@ namespace embree
                        << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
                        << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 1
thirdparty/embree-aarch64/common/simd/vboold4_avx512.h → thirdparty/embree/common/simd/vboold4_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide AVX-512 bool type */
   /* 4-wide AVX-512 bool type */
@@ -138,3 +146,11 @@ namespace embree
     return cout << ">";
     return cout << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 14
thirdparty/embree-aarch64/common/simd/vboold8_avx512.h → thirdparty/embree/common/simd/vboold8_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX-512 bool type */
   /* 8-wide AVX-512 bool type */
@@ -32,25 +40,12 @@ namespace embree
 
 
     /* return int8 mask */
     /* return int8 mask */
     __forceinline __m128i mask8() const {
     __forceinline __m128i mask8() const {
-#if defined(__AVX512BW__)
       return _mm_movm_epi8(v);
       return _mm_movm_epi8(v);
-#else
-      const __m512i f = _mm512_set1_epi64(0);
-      const __m512i t = _mm512_set1_epi64(-1);
-      const __m512i m =  _mm512_mask_or_epi64(f,v,t,t); 
-      return _mm512_cvtepi64_epi8(m);
-#endif
     }
     }
 
 
     /* return int64 mask */
     /* return int64 mask */
     __forceinline __m512i mask64() const { 
     __forceinline __m512i mask64() const { 
-#if defined(__AVX512DQ__)
       return _mm512_movm_epi64(v);
       return _mm512_movm_epi64(v);
-#else
-      const __m512i f = _mm512_set1_epi64(0);
-      const __m512i t = _mm512_set1_epi64(-1);
-      return _mm512_mask_or_epi64(f,v,t,t); 
-#endif
     }
     }
 
 
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -146,3 +141,11 @@ namespace embree
     return cout << ">";
     return cout << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 14
thirdparty/embree-aarch64/common/simd/vboolf16_avx512.h → thirdparty/embree/common/simd/vboolf16_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 16-wide AVX-512 bool type */
   /* 16-wide AVX-512 bool type */
@@ -33,25 +41,12 @@ namespace embree
 
 
     /* return int8 mask */
     /* return int8 mask */
     __forceinline __m128i mask8() const {
     __forceinline __m128i mask8() const {
-#if defined(__AVX512BW__)
       return _mm_movm_epi8(v);
       return _mm_movm_epi8(v);
-#else
-      const __m512i f = _mm512_set1_epi32(0);
-      const __m512i t = _mm512_set1_epi32(-1);
-      const __m512i m =  _mm512_mask_or_epi32(f,v,t,t);
-      return _mm512_cvtepi32_epi8(m);
-#endif
     }
     }
 
 
     /* return int32 mask */
     /* return int32 mask */
     __forceinline __m512i mask32() const {
     __forceinline __m512i mask32() const {
-#if defined(__AVX512DQ__)
       return _mm512_movm_epi32(v);
       return _mm512_movm_epi32(v);
-#else
-      const __m512i f = _mm512_set1_epi32(0);
-      const __m512i t = _mm512_set1_epi32(-1);
-      return _mm512_mask_or_epi32(f,v,t,t);
-#endif
     }
     }
 
 
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -148,3 +143,11 @@ namespace embree
     return cout << ">";
     return cout << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 1
thirdparty/embree-aarch64/common/simd/vboolf4_avx512.h → thirdparty/embree/common/simd/vboolf4_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide AVX-512 bool type */
   /* 4-wide AVX-512 bool type */
@@ -141,3 +149,11 @@ namespace embree
     return cout << ">";
     return cout << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 21 - 30
thirdparty/embree-aarch64/common/simd/vboolf4_sse2.h → thirdparty/embree/common/simd/vboolf4_sse2.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide SSE bool type */
   /* 4-wide SSE bool type */
@@ -37,13 +45,9 @@ namespace embree
       : v(mm_lookupmask_ps[(size_t(b) << 3) | (size_t(a) << 2) | (size_t(b) << 1) | size_t(a)]) {}
       : v(mm_lookupmask_ps[(size_t(b) << 3) | (size_t(a) << 2) | (size_t(b) << 1) | size_t(a)]) {}
     __forceinline vboolf(bool a, bool b, bool c, bool d)
     __forceinline vboolf(bool a, bool b, bool c, bool d)
       : v(mm_lookupmask_ps[(size_t(d) << 3) | (size_t(c) << 2) | (size_t(b) << 1) | size_t(a)]) {}
       : v(mm_lookupmask_ps[(size_t(d) << 3) | (size_t(c) << 2) | (size_t(b) << 1) | size_t(a)]) {}
-#if defined(__aarch64__) && defined(BUILD_IOS)
-      __forceinline vboolf(int mask) { v = mm_lookupmask_ps[mask]; }
-      __forceinline vboolf(unsigned int mask) { v = mm_lookupmask_ps[mask]; }
-#else
     __forceinline vboolf(int mask) { assert(mask >= 0 && mask < 16); v = mm_lookupmask_ps[mask]; }
     __forceinline vboolf(int mask) { assert(mask >= 0 && mask < 16); v = mm_lookupmask_ps[mask]; }
     __forceinline vboolf(unsigned int mask) { assert(mask < 16); v = mm_lookupmask_ps[mask]; }
     __forceinline vboolf(unsigned int mask) { assert(mask < 16); v = mm_lookupmask_ps[mask]; }
-#endif
+
     /* return int32 mask */
     /* return int32 mask */
     __forceinline __m128i mask32() const { 
     __forceinline __m128i mask32() const { 
       return _mm_castps_si128(v);
       return _mm_castps_si128(v);
@@ -60,13 +64,8 @@ namespace embree
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined(__aarch64__) && defined(BUILD_IOS)
-      __forceinline bool operator [](size_t index) const { return (_mm_movemask_ps(v) >> index) & 1; }
-      __forceinline int& operator [](size_t index)       { return i[index]; }
-#else
     __forceinline bool operator [](size_t index) const { assert(index < 4); return (_mm_movemask_ps(v) >> index) & 1; }
     __forceinline bool operator [](size_t index) const { assert(index < 4); return (_mm_movemask_ps(v) >> index) & 1; }
     __forceinline int& operator [](size_t index)       { assert(index < 4); return i[index]; }
     __forceinline int& operator [](size_t index)       { assert(index < 4); return i[index]; }
-#endif
   };
   };
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -101,7 +100,7 @@ namespace embree
   __forceinline vboolf4 operator ==(const vboolf4& a, const vboolf4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
   __forceinline vboolf4 operator ==(const vboolf4& a, const vboolf4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
   
   
   __forceinline vboolf4 select(const vboolf4& m, const vboolf4& t, const vboolf4& f) {
   __forceinline vboolf4 select(const vboolf4& m, const vboolf4& t, const vboolf4& f) {
-#if (defined(__aarch64__) && defined(BUILD_IOS)) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     return _mm_blendv_ps(f, t, m); 
     return _mm_blendv_ps(f, t, m); 
 #else
 #else
     return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f)); 
     return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f)); 
@@ -115,17 +114,6 @@ namespace embree
   __forceinline vboolf4 unpacklo(const vboolf4& a, const vboolf4& b) { return _mm_unpacklo_ps(a, b); }
   __forceinline vboolf4 unpacklo(const vboolf4& a, const vboolf4& b) { return _mm_unpacklo_ps(a, b); }
   __forceinline vboolf4 unpackhi(const vboolf4& a, const vboolf4& b) { return _mm_unpackhi_ps(a, b); }
   __forceinline vboolf4 unpackhi(const vboolf4& a, const vboolf4& b) { return _mm_unpackhi_ps(a, b); }
 
 
-#if defined(__aarch64__)
-  template<int i0, int i1, int i2, int i3>
-  __forceinline vboolf4 shuffle(const vboolf4& v) {
-    return vreinterpretq_f32_u8(vqtbl1q_u8( vreinterpretq_u8_s32(v), _MN_SHUFFLE(i0, i1, i2, i3)));
-  }
-
-  template<int i0, int i1, int i2, int i3>
-  __forceinline vboolf4 shuffle(const vboolf4& a, const vboolf4& b) {
-    return vreinterpretq_f32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
-  }
-#else
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
   __forceinline vboolf4 shuffle(const vboolf4& v) {
   __forceinline vboolf4 shuffle(const vboolf4& v) {
     return _mm_castsi128_ps(_mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0)));
     return _mm_castsi128_ps(_mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0)));
@@ -135,8 +123,7 @@ namespace embree
   __forceinline vboolf4 shuffle(const vboolf4& a, const vboolf4& b) {
   __forceinline vboolf4 shuffle(const vboolf4& a, const vboolf4& b) {
     return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
     return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
   }
   }
-#endif
-                                                                
+
   template<int i0>
   template<int i0>
   __forceinline vboolf4 shuffle(const vboolf4& v) {
   __forceinline vboolf4 shuffle(const vboolf4& v) {
     return shuffle<i0,i0,i0,i0>(v);
     return shuffle<i0,i0,i0,i0>(v);
@@ -148,7 +135,7 @@ namespace embree
   template<> __forceinline vboolf4 shuffle<0, 1, 0, 1>(const vboolf4& v) { return _mm_castpd_ps(_mm_movedup_pd(v)); }
   template<> __forceinline vboolf4 shuffle<0, 1, 0, 1>(const vboolf4& v) { return _mm_castpd_ps(_mm_movedup_pd(v)); }
 #endif
 #endif
 
 
-#if defined(__SSE4_1__) && !defined(__aarch64__)
+#if defined(__SSE4_1__)
   template<int dst, int src, int clr> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
   template<int dst, int src, int clr> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
   template<int dst, int src> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return insert<dst, src, 0>(a, b); }
   template<int dst, int src> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return insert<dst, src, 0>(a, b); }
   template<int dst> __forceinline vboolf4 insert(const vboolf4& a, const bool b) { return insert<dst, 0>(a, vboolf4(b)); }
   template<int dst> __forceinline vboolf4 insert(const vboolf4& a, const bool b) { return insert<dst, 0>(a, vboolf4(b)); }
@@ -170,14 +157,10 @@ namespace embree
   __forceinline bool none(const vboolf4& valid, const vboolf4& b) { return none(valid & b); }
   __forceinline bool none(const vboolf4& valid, const vboolf4& b) { return none(valid & b); }
   
   
   __forceinline size_t movemask(const vboolf4& a) { return _mm_movemask_ps(a); }
   __forceinline size_t movemask(const vboolf4& a) { return _mm_movemask_ps(a); }
-#if defined(__aarch64__) && defined(BUILD_IOS)
-__forceinline size_t popcnt(const vboolf4& a) { return _mm_movemask_popcnt_ps(a); }
-#else
 #if defined(__SSE4_2__)
 #if defined(__SSE4_2__)
   __forceinline size_t popcnt(const vboolf4& a) { return popcnt((size_t)_mm_movemask_ps(a)); }
   __forceinline size_t popcnt(const vboolf4& a) { return popcnt((size_t)_mm_movemask_ps(a)); }
 #else
 #else
   __forceinline size_t popcnt(const vboolf4& a) { return bool(a[0])+bool(a[1])+bool(a[2])+bool(a[3]); }
   __forceinline size_t popcnt(const vboolf4& a) { return bool(a[0])+bool(a[1])+bool(a[2])+bool(a[3]); }
-#endif
 #endif
 #endif
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -196,3 +179,11 @@ __forceinline size_t popcnt(const vboolf4& a) { return _mm_movemask_popcnt_ps(a)
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 18 - 5
thirdparty/embree-aarch64/common/simd/vboolf8_avx.h → thirdparty/embree/common/simd/vboolf8_avx.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX bool type */
   /* 8-wide AVX bool type */
@@ -68,11 +76,8 @@ namespace embree
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
 
 
     __forceinline vboolf(FalseTy) : v(_mm256_setzero_ps()) {}
     __forceinline vboolf(FalseTy) : v(_mm256_setzero_ps()) {}
-#if !defined(__aarch64__)
     __forceinline vboolf(TrueTy)  : v(_mm256_cmp_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _CMP_EQ_OQ)) {}
     __forceinline vboolf(TrueTy)  : v(_mm256_cmp_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _CMP_EQ_OQ)) {}
-#else
-    __forceinline vboolf(TrueTy)  : v(_mm256_cmpeq_ps(_mm256_setzero_ps(), _mm256_setzero_ps())) {}
-#endif
+
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -187,3 +192,11 @@ namespace embree
                        << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
                        << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 1
thirdparty/embree-aarch64/common/simd/vboolf8_avx512.h → thirdparty/embree/common/simd/vboolf8_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX-512 bool type */
   /* 8-wide AVX-512 bool type */
@@ -141,3 +149,11 @@ namespace embree
     return cout << ">";
     return cout << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 18 - 21
thirdparty/embree-aarch64/common/simd/vdouble4_avx.h → thirdparty/embree/common/simd/vdouble4_avx.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 { 
 { 
   /* 4-wide AVX 64-bit double type */
   /* 4-wide AVX 64-bit double type */
@@ -181,20 +189,13 @@ namespace embree
   __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GE); }
   __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GE); }
   __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GT); }
   __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GT); }
   __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_LE); }
   __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_LE); }
-#elif !defined(__aarch64__)
+#else
   __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OQ);  }
   __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OQ);  }
   __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_UQ); }
   __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_UQ); }
   __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS);  }
   __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS);  }
   __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); }
   __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); }
   __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); }
   __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); }
   __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS);  }
   __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS);  }
-#else
-  __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmpeq_pd(a, b);  }
-  __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmpneq_pd(a, b); }
-  __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmplt_pd(a, b);  }
-  __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmpnlt_pd(a, b); }
-  __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmpnle_pd(a, b); }
-  __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmple_pd(a, b);  }
 #endif
 #endif
 
 
   __forceinline vboold4 operator ==(const vdouble4& a, double          b) { return a == vdouble4(b); }
   __forceinline vboold4 operator ==(const vdouble4& a, double          b) { return a == vdouble4(b); }
@@ -246,18 +247,6 @@ namespace embree
 #endif
 #endif
   }
   }
 
 
-  __forceinline void xchg(const vboold4& m, vdouble4& a, vdouble4& b) {
-    const vdouble4 c = a; a = select(m,b,a); b = select(m,c,b);
-  }
-
-  __forceinline vboold4 test(const vdouble4& a, const vdouble4& b) {
-#if defined(__AVX512VL__)
-    return _mm256_test_epi64_mask(_mm256_castpd_si256(a),_mm256_castpd_si256(b));
-#else
-    return _mm256_testz_si256(_mm256_castpd_si256(a),_mm256_castpd_si256(b));
-#endif
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Movement/Shifting/Shuffling Functions
   // Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -322,3 +311,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 22
thirdparty/embree-aarch64/common/simd/vdouble8_avx512.h → thirdparty/embree/common/simd/vdouble8_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX-512 64-bit double type */
   /* 8-wide AVX-512 64-bit double type */
@@ -91,15 +99,6 @@ namespace embree
       _mm512_mask_store_pd(addr, mask, v2);
       _mm512_mask_store_pd(addr, mask, v2);
     }
     }
 
 
-    /* pass by value to avoid compiler generating inefficient code */
-    static __forceinline void storeu_compact(const vboold8 mask,void * addr, const vdouble8& reg) {
-      _mm512_mask_compressstoreu_pd(addr, mask, reg);
-    }
-
-    static __forceinline vdouble8 compact64bit(const vboold8& mask, vdouble8& v) {
-      return _mm512_mask_compress_pd(v, mask, v);
-    }
-
     static __forceinline vdouble8 compact(const vboold8& mask, vdouble8& v) {
     static __forceinline vdouble8 compact(const vboold8& mask, vdouble8& v) {
       return _mm512_mask_compress_pd(v, mask, v);
       return _mm512_mask_compress_pd(v, mask, v);
     }
     }
@@ -260,18 +259,6 @@ namespace embree
     return _mm512_mask_or_pd(f,m,t,t);
     return _mm512_mask_or_pd(f,m,t,t);
   }
   }
 
 
-  __forceinline void xchg(const vboold8& m, vdouble8& a, vdouble8& b) {
-    const vdouble8 c = a; a = select(m,b,a); b = select(m,c,b);
-  }
-
-  __forceinline vboold8 test(const vboold8& m, const vdouble8& a, const vdouble8& b) {
-    return _mm512_mask_test_epi64_mask(m,_mm512_castpd_si512(a),_mm512_castpd_si512(b));
-  }
-
-  __forceinline vboold8 test(const vdouble8& a, const vdouble8& b) {
-    return _mm512_test_epi64_mask(_mm512_castpd_si512(a),_mm512_castpd_si512(b));
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Movement/Shifting/Shuffling Functions
   // Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -354,3 +341,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 25 - 181
thirdparty/embree-aarch64/common/simd/vfloat16_avx512.h → thirdparty/embree/common/simd/vfloat16_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 16-wide AVX-512 float type */
   /* 16-wide AVX-512 float type */
@@ -73,11 +81,11 @@ namespace embree
     }
     }
 
 
     /* WARNING: due to f64x4 the mask is considered as an 8bit mask */
     /* WARNING: due to f64x4 the mask is considered as an 8bit mask */
-    __forceinline vfloat(const vboolf16& mask, const vfloat8& a, const vfloat8& b) {
+    /*__forceinline vfloat(const vboolf16& mask, const vfloat8& a, const vfloat8& b) {
       __m512d aa = _mm512_broadcast_f64x4(_mm256_castps_pd(a));
       __m512d aa = _mm512_broadcast_f64x4(_mm256_castps_pd(a));
       aa = _mm512_mask_broadcast_f64x4(aa,mask,_mm256_castps_pd(b));
       aa = _mm512_mask_broadcast_f64x4(aa,mask,_mm256_castps_pd(b));
       v = _mm512_castpd_ps(aa);
       v = _mm512_castpd_ps(aa);
-    }
+      }*/
     
     
     __forceinline explicit vfloat(const vint16& a) {
     __forceinline explicit vfloat(const vint16& a) {
       v = _mm512_cvtepi32_ps(a);
       v = _mm512_cvtepi32_ps(a);
@@ -123,30 +131,6 @@ namespace embree
       return _mm512_set1_ps(*f);
       return _mm512_set1_ps(*f);
     }
     }
 
 
-    static __forceinline vfloat16 compact(const vboolf16& mask, vfloat16 &v) {
-      return _mm512_mask_compress_ps(v, mask, v);
-    }
-    static __forceinline vfloat16 compact(const vboolf16& mask, vfloat16 &a, const vfloat16& b) {
-      return _mm512_mask_compress_ps(a, mask, b);
-    }
-
-    static __forceinline vfloat16 expand(const vboolf16& mask, const vfloat16& a, vfloat16& b) {
-      return _mm512_mask_expand_ps(b, mask, a);
-    }
-
-    static __forceinline vfloat16 loadu_compact(const vboolf16& mask, const void* ptr) {
-      return _mm512_mask_expandloadu_ps(_mm512_setzero_ps(), mask, (float*)ptr);
-    }
-
-    static __forceinline void storeu_compact(const vboolf16& mask, float *addr, const vfloat16 reg) {
-      _mm512_mask_compressstoreu_ps(addr, mask, reg);
-    }
-    
-    static __forceinline void storeu_compact_single(const vboolf16& mask, float * addr, const vfloat16& reg) {
-      //_mm512_mask_compressstoreu_ps(addr,mask,reg);
-      *addr = mm512_cvtss_f32(_mm512_mask_compress_ps(reg, mask, reg));
-    }
-
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vfloat16 gather(const float* ptr, const vint16& index) {
     static __forceinline vfloat16 gather(const float* ptr, const vint16& index) {
       return _mm512_i32gather_ps(index, ptr, scale);
       return _mm512_i32gather_ps(index, ptr, scale);
@@ -194,12 +178,8 @@ namespace embree
   __forceinline vfloat16 signmsk(const vfloat16& a) { return _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a),_mm512_set1_epi32(0x80000000))); }
   __forceinline vfloat16 signmsk(const vfloat16& a) { return _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a),_mm512_set1_epi32(0x80000000))); }
 
 
   __forceinline vfloat16 rcp(const vfloat16& a) {
   __forceinline vfloat16 rcp(const vfloat16& a) {
-#if defined(__AVX512ER__)
-    return _mm512_rcp28_ps(a);
-#else
     const vfloat16 r = _mm512_rcp14_ps(a);
     const vfloat16 r = _mm512_rcp14_ps(a);
     return _mm512_mul_ps(r, _mm512_fnmadd_ps(r, a, vfloat16(2.0f)));
     return _mm512_mul_ps(r, _mm512_fnmadd_ps(r, a, vfloat16(2.0f)));
-#endif
   }
   }
 
 
   __forceinline vfloat16 sqr (const vfloat16& a) { return _mm512_mul_ps(a,a); }
   __forceinline vfloat16 sqr (const vfloat16& a) { return _mm512_mul_ps(a,a); }
@@ -207,13 +187,9 @@ namespace embree
 
 
   __forceinline vfloat16 rsqrt(const vfloat16& a)
   __forceinline vfloat16 rsqrt(const vfloat16& a)
   {
   {
-#if defined(__AVX512VL__)
     const vfloat16 r = _mm512_rsqrt14_ps(a);
     const vfloat16 r = _mm512_rsqrt14_ps(a);
     return _mm512_fmadd_ps(_mm512_set1_ps(1.5f), r,
     return _mm512_fmadd_ps(_mm512_set1_ps(1.5f), r,
                            _mm512_mul_ps(_mm512_mul_ps(_mm512_mul_ps(a, _mm512_set1_ps(-0.5f)), r), _mm512_mul_ps(r, r))); 
                            _mm512_mul_ps(_mm512_mul_ps(_mm512_mul_ps(a, _mm512_set1_ps(-0.5f)), r), _mm512_mul_ps(r, r))); 
-#else
-    return _mm512_rsqrt28_ps(a);
-#endif
   }
   }
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -242,54 +218,26 @@ namespace embree
     return  _mm512_castsi512_ps(_mm512_xor_epi32(_mm512_castps_si512(a),_mm512_castps_si512(b))); 
     return  _mm512_castsi512_ps(_mm512_xor_epi32(_mm512_castps_si512(a),_mm512_castps_si512(b))); 
   }
   }
   
   
-  __forceinline vfloat16 min(const vfloat16& a, const vfloat16& b) {
-    return _mm512_min_ps(a,b); 
-  }
-  __forceinline vfloat16 min(const vfloat16& a, float b) {
-    return _mm512_min_ps(a,vfloat16(b));
-  }
-  __forceinline vfloat16 min(const float& a, const vfloat16& b) {
-    return _mm512_min_ps(vfloat16(a),b);
-  }
-
-  __forceinline vfloat16 max(const vfloat16& a, const vfloat16& b) {
-    return _mm512_max_ps(a,b); 
-  }
-  __forceinline vfloat16 max(const vfloat16& a, float b) {
-    return _mm512_max_ps(a,vfloat16(b));
-  }
-  __forceinline vfloat16 max(const float& a, const vfloat16& b) {
-    return _mm512_max_ps(vfloat16(a),b);
-  }
+  __forceinline vfloat16 min(const vfloat16& a, const vfloat16& b) { return _mm512_min_ps(a,b);  }
+  __forceinline vfloat16 min(const vfloat16& a, float           b) { return _mm512_min_ps(a,vfloat16(b)); }
+  __forceinline vfloat16 min(const float&    a, const vfloat16& b) { return _mm512_min_ps(vfloat16(a),b); }
 
 
-  __forceinline vfloat16 mask_add(const vboolf16& mask, const vfloat16& c, const vfloat16& a, const vfloat16& b) { return _mm512_mask_add_ps (c,mask,a,b); }
-  __forceinline vfloat16 mask_min(const vboolf16& mask, const vfloat16& c, const vfloat16& a, const vfloat16& b) {
-    return _mm512_mask_min_ps(c,mask,a,b); 
-  }; 
-  __forceinline vfloat16 mask_max(const vboolf16& mask, const vfloat16& c, const vfloat16& a, const vfloat16& b) {
-    return _mm512_mask_max_ps(c,mask,a,b); 
-  }; 
+  __forceinline vfloat16 max(const vfloat16& a, const vfloat16& b) { return _mm512_max_ps(a,b); }
+  __forceinline vfloat16 max(const vfloat16& a, float           b) { return _mm512_max_ps(a,vfloat16(b)); }
+  __forceinline vfloat16 max(const float&    a, const vfloat16& b) { return _mm512_max_ps(vfloat16(a),b); }
 
 
   __forceinline vfloat16 mini(const vfloat16& a, const vfloat16& b) {
   __forceinline vfloat16 mini(const vfloat16& a, const vfloat16& b) {
-#if !defined(__AVX512ER__) // SKX
     const vint16 ai = _mm512_castps_si512(a);
     const vint16 ai = _mm512_castps_si512(a);
     const vint16 bi = _mm512_castps_si512(b);
     const vint16 bi = _mm512_castps_si512(b);
     const vint16 ci = _mm512_min_epi32(ai,bi);
     const vint16 ci = _mm512_min_epi32(ai,bi);
     return _mm512_castsi512_ps(ci);
     return _mm512_castsi512_ps(ci);
-#else // KNL
-    return min(a,b);
-#endif
   }
   }
 
 
   __forceinline vfloat16 maxi(const vfloat16& a, const vfloat16& b) {
   __forceinline vfloat16 maxi(const vfloat16& a, const vfloat16& b) {
-#if !defined(__AVX512ER__) // SKX
     const vint16 ai = _mm512_castps_si512(a);
     const vint16 ai = _mm512_castps_si512(a);
     const vint16 bi = _mm512_castps_si512(b);
     const vint16 bi = _mm512_castps_si512(b);
     const vint16 ci = _mm512_max_epi32(ai,bi);
     const vint16 ci = _mm512_max_epi32(ai,bi);
     return _mm512_castsi512_ps(ci);
     return _mm512_castsi512_ps(ci);
-#else // KNL
-    return max(a,b);
-#endif
   }
   }
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -300,43 +248,6 @@ namespace embree
   __forceinline vfloat16 msub (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(a,b,c); }
   __forceinline vfloat16 msub (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(a,b,c); }
   __forceinline vfloat16 nmadd(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmadd_ps(a,b,c); }
   __forceinline vfloat16 nmadd(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmadd_ps(a,b,c); }
   __forceinline vfloat16 nmsub(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmsub_ps(a,b,c); }
   __forceinline vfloat16 nmsub(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmsub_ps(a,b,c); }
-
-  __forceinline vfloat16 mask_msub(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_fmsub_ps(a,mask,b,c); }
-  
-  __forceinline vfloat16 madd231 (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_ps(c,b,a); }
-  __forceinline vfloat16 msub213 (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(a,b,c); }
-  __forceinline vfloat16 msub231 (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(c,b,a); }
-  __forceinline vfloat16 msubr231(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmadd_ps(c,b,a); }
-
-
-  ////////////////////////////////////////////////////////////////////////////////
-  /// Operators with rounding
-  ////////////////////////////////////////////////////////////////////////////////
-  
-  __forceinline vfloat16 madd_round_down(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_round_ps(a,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 madd_round_up  (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_round_ps(a,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
-  __forceinline vfloat16 mul_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_mul_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 mul_round_up  (const vfloat16& a, const vfloat16& b) { return _mm512_mul_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
-  __forceinline vfloat16 add_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_add_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 add_round_up  (const vfloat16& a, const vfloat16& b) { return _mm512_add_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
-  __forceinline vfloat16 sub_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_sub_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 sub_round_up  (const vfloat16& a, const vfloat16& b) { return _mm512_sub_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
-  __forceinline vfloat16 div_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_div_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 div_round_up  (const vfloat16& a, const vfloat16& b) { return _mm512_div_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
-  __forceinline vfloat16 mask_msub_round_down(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_fmsub_round_ps(a,mask,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 mask_msub_round_up  (const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_fmsub_round_ps(a,mask,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-  
-  __forceinline vfloat16 mask_mul_round_down(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_mul_round_ps(a,mask,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 mask_mul_round_up  (const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_mul_round_ps(a,mask,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
-  __forceinline vfloat16 mask_sub_round_down(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_sub_round_ps(a,mask,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
-  __forceinline vfloat16 mask_sub_round_up  (const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_sub_round_ps(a,mask,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
-
   
   
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Assignment Operators
   /// Assignment Operators
@@ -404,13 +315,6 @@ namespace embree
     return madd(t,b-a,a);
     return madd(t,b-a,a);
   }
   }
 
 
-  __forceinline void xchg(vboolf16 m, vfloat16& a, vfloat16& b)
-  {
-    vfloat16 c = a;
-    a = select(m,b,a);
-    b = select(m,c,b); 
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Rounding Functions
   /// Rounding Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -455,24 +359,6 @@ namespace embree
     return _mm512_shuffle_f32x4(v, v, _MM_SHUFFLE(i3, i2, i1, i0));
     return _mm512_shuffle_f32x4(v, v, _MM_SHUFFLE(i3, i2, i1, i0));
   }
   }
 
 
-  __forceinline vfloat16 interleave_even(const vfloat16& a, const vfloat16& b) {
-    return _mm512_castsi512_ps(_mm512_mask_shuffle_epi32(_mm512_castps_si512(a), mm512_int2mask(0xaaaa), _mm512_castps_si512(b), (_MM_PERM_ENUM)0xb1));
-  }
-
-  __forceinline vfloat16 interleave_odd(const vfloat16& a, const vfloat16& b) {
-    return _mm512_castsi512_ps(_mm512_mask_shuffle_epi32(_mm512_castps_si512(b), mm512_int2mask(0x5555), _mm512_castps_si512(a), (_MM_PERM_ENUM)0xb1));
-  }
-
-  __forceinline vfloat16 interleave2_even(const vfloat16& a, const vfloat16& b) {
-    /* mask should be 8-bit but is 16-bit to reuse for interleave_even */
-    return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(a), mm512_int2mask(0xaaaa), _mm512_castps_si512(b), (_MM_PERM_ENUM)0xb1));
-  }
-
-  __forceinline vfloat16 interleave2_odd(const vfloat16& a, const vfloat16& b) {
-    /* mask should be 8-bit but is 16-bit to reuse for interleave_odd */
-    return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(b), mm512_int2mask(0x5555), _mm512_castps_si512(a), (_MM_PERM_ENUM)0xb1));
-  }
-
   __forceinline vfloat16 interleave4_even(const vfloat16& a, const vfloat16& b) {
   __forceinline vfloat16 interleave4_even(const vfloat16& a, const vfloat16& b) {
     return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(a), mm512_int2mask(0xcc), _mm512_castps_si512(b), (_MM_PERM_ENUM)0x4e));
     return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(a), mm512_int2mask(0xcc), _mm512_castps_si512(b), (_MM_PERM_ENUM)0x4e));
   }
   }
@@ -537,17 +423,6 @@ namespace embree
   __forceinline void transpose(const vfloat16& r0, const vfloat16& r1, const vfloat16& r2, const vfloat16& r3,
   __forceinline void transpose(const vfloat16& r0, const vfloat16& r1, const vfloat16& r2, const vfloat16& r3,
                                vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3)
                                vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3)
   {
   {
-#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
-    vfloat16 a0a1_c0c1 = interleave_even(r0, r1);
-    vfloat16 a2a3_c2c3 = interleave_even(r2, r3);
-    vfloat16 b0b1_d0d1 = interleave_odd (r0, r1);
-    vfloat16 b2b3_d2d3 = interleave_odd (r2, r3);
-
-    c0 = interleave2_even(a0a1_c0c1, a2a3_c2c3);
-    c1 = interleave2_even(b0b1_d0d1, b2b3_d2d3);
-    c2 = interleave2_odd (a0a1_c0c1, a2a3_c2c3);
-    c3 = interleave2_odd (b0b1_d0d1, b2b3_d2d3);
-#else
     vfloat16 a0a2_b0b2 = unpacklo(r0, r2);
     vfloat16 a0a2_b0b2 = unpacklo(r0, r2);
     vfloat16 c0c2_d0d2 = unpackhi(r0, r2);
     vfloat16 c0c2_d0d2 = unpackhi(r0, r2);
     vfloat16 a1a3_b1b3 = unpacklo(r1, r3);
     vfloat16 a1a3_b1b3 = unpacklo(r1, r3);
@@ -557,7 +432,6 @@ namespace embree
     c1 = unpackhi(a0a2_b0b2, a1a3_b1b3);
     c1 = unpackhi(a0a2_b0b2, a1a3_b1b3);
     c2 = unpacklo(c0c2_d0d2, c1c3_d1d3);
     c2 = unpacklo(c0c2_d0d2, c1c3_d1d3);
     c3 = unpackhi(c0c2_d0d2, c1c3_d1d3);
     c3 = unpackhi(c0c2_d0d2, c1c3_d1d3);
-#endif
   }
   }
 
 
   __forceinline void transpose(const vfloat4& r0,  const vfloat4& r1,  const vfloat4& r2,  const vfloat4& r3,
   __forceinline void transpose(const vfloat4& r0,  const vfloat4& r1,  const vfloat4& r2,  const vfloat4& r3,
@@ -715,44 +589,6 @@ namespace embree
     return v;  
     return v;  
   }
   }
 
 
-  ////////////////////////////////////////////////////////////////////////////////
-  /// Memory load and store operations
-  ////////////////////////////////////////////////////////////////////////////////
-
-  __forceinline vfloat16 loadAOS4to16f(const float& x, const float& y, const float& z)
-  {
-    vfloat16 f = zero;
-    f = select(0x1111,vfloat16::broadcast(&x),f);
-    f = select(0x2222,vfloat16::broadcast(&y),f);
-    f = select(0x4444,vfloat16::broadcast(&z),f);
-    return f;
-  }
-
-  __forceinline vfloat16 loadAOS4to16f(unsigned int index,
-                                       const vfloat16& x,
-                                       const vfloat16& y,
-                                       const vfloat16& z)
-  {
-    vfloat16 f = zero;
-    f = select(0x1111,vfloat16::broadcast((float*)&x + index),f);
-    f = select(0x2222,vfloat16::broadcast((float*)&y + index),f);
-    f = select(0x4444,vfloat16::broadcast((float*)&z + index),f);
-    return f;
-  }
-
-  __forceinline vfloat16 loadAOS4to16f(unsigned int index,
-                                       const vfloat16& x,
-                                       const vfloat16& y,
-                                       const vfloat16& z,
-                                       const vfloat16& fill)
-  {
-    vfloat16 f = fill;
-    f = select(0x1111,vfloat16::broadcast((float*)&x + index),f);
-    f = select(0x2222,vfloat16::broadcast((float*)&y + index),f);
-    f = select(0x4444,vfloat16::broadcast((float*)&z + index),f);
-    return f;
-  }
-
   __forceinline vfloat16 rcp_safe(const vfloat16& a) {
   __forceinline vfloat16 rcp_safe(const vfloat16& a) {
     return rcp(select(a != vfloat16(zero), a, vfloat16(min_rcp_input)));
     return rcp(select(a != vfloat16(zero), a, vfloat16(min_rcp_input)));
   }
   }
@@ -769,3 +605,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 111 - 314
thirdparty/embree-aarch64/common/simd/vfloat4_sse2.h → thirdparty/embree/common/simd/vfloat4_sse2.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide SSE float type */
   /* 4-wide SSE float type */
@@ -10,18 +18,18 @@ namespace embree
   struct vfloat<4>
   struct vfloat<4>
   {
   {
     ALIGNED_STRUCT_(16);
     ALIGNED_STRUCT_(16);
-
+    
     typedef vboolf4 Bool;
     typedef vboolf4 Bool;
     typedef vint4   Int;
     typedef vint4   Int;
     typedef vfloat4 Float;
     typedef vfloat4 Float;
-
+    
     enum  { size = 4 };                        // number of SIMD elements
     enum  { size = 4 };                        // number of SIMD elements
     union { __m128 v; float f[4]; int i[4]; }; // data
     union { __m128 v; float f[4]; int i[4]; }; // data
 
 
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Constructors, Assignment & Cast Operators
     /// Constructors, Assignment & Cast Operators
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
-
+    
     __forceinline vfloat() {}
     __forceinline vfloat() {}
     __forceinline vfloat(const vfloat4& other) { v = other.v; }
     __forceinline vfloat(const vfloat4& other) { v = other.v; }
     __forceinline vfloat4& operator =(const vfloat4& other) { v = other.v; return *this; }
     __forceinline vfloat4& operator =(const vfloat4& other) { v = other.v; return *this; }
@@ -34,19 +42,14 @@ namespace embree
     __forceinline vfloat(float a, float b, float c, float d) : v(_mm_set_ps(d, c, b, a)) {}
     __forceinline vfloat(float a, float b, float c, float d) : v(_mm_set_ps(d, c, b, a)) {}
 
 
     __forceinline explicit vfloat(const vint4& a) : v(_mm_cvtepi32_ps(a)) {}
     __forceinline explicit vfloat(const vint4& a) : v(_mm_cvtepi32_ps(a)) {}
-#if defined(__aarch64__)
-    __forceinline explicit vfloat(const vuint4& x) {
-        v = vcvtq_f32_u32(vreinterpretq_u32_s32(x.v));
-    }
-#else
     __forceinline explicit vfloat(const vuint4& x) {
     __forceinline explicit vfloat(const vuint4& x) {
       const __m128i a   = _mm_and_si128(x,_mm_set1_epi32(0x7FFFFFFF));
       const __m128i a   = _mm_and_si128(x,_mm_set1_epi32(0x7FFFFFFF));
-      const __m128i b   = _mm_and_si128(_mm_srai_epi32(x,31),_mm_set1_epi32(0x4F000000)); //0x4F000000 = 2^31
+      const __m128i b   = _mm_and_si128(_mm_srai_epi32(x,31),_mm_set1_epi32(0x4F000000)); //0x4F000000 = 2^31 
       const __m128  af  = _mm_cvtepi32_ps(a);
       const __m128  af  = _mm_cvtepi32_ps(a);
-      const __m128  bf  = _mm_castsi128_ps(b);
+      const __m128  bf  = _mm_castsi128_ps(b);  
       v  = _mm_add_ps(af,bf);
       v  = _mm_add_ps(af,bf);
     }
     }
-#endif
+
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Constants
     /// Constants
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -71,13 +74,6 @@ namespace embree
 
 
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
 
 
-    static __forceinline vfloat4 compact(const vboolf4& mask, vfloat4 &v) {
-      return _mm_mask_compress_ps(v, mask, v);
-    }
-    static __forceinline vfloat4 compact(const vboolf4& mask, vfloat4 &a, const vfloat4& b) {
-      return _mm_mask_compress_ps(a, mask, b);
-    }
-
     static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_ps (_mm_setzero_ps(),mask,(float*)ptr); }
     static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_ps (_mm_setzero_ps(),mask,(float*)ptr); }
     static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_ps(_mm_setzero_ps(),mask,(float*)ptr); }
     static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_ps(_mm_setzero_ps(),mask,(float*)ptr); }
 
 
@@ -107,44 +103,32 @@ namespace embree
 #if defined (__SSE4_1__)
 #if defined (__SSE4_1__)
     return _mm_castsi128_ps(_mm_stream_load_si128((__m128i*)ptr));
     return _mm_castsi128_ps(_mm_stream_load_si128((__m128i*)ptr));
 #else
 #else
-    return _mm_load_ps(ptr);
+    return _mm_load_ps(ptr); 
 #endif
 #endif
   }
   }
 
 
-#if defined(__aarch64__)
-    static __forceinline vfloat4 load(const int8_t* ptr) {
-        return __m128(_mm_load4epi8_f32(((__m128i*)ptr)));
-    }
-#elif defined(__SSE4_1__)
-    static __forceinline vfloat4 load(const int8_t* ptr) {
+#if defined(__SSE4_1__)
+    static __forceinline vfloat4 load(const char* ptr) {
       return _mm_cvtepi32_ps(_mm_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
       return _mm_cvtepi32_ps(_mm_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
     }
     }
 #else
 #else
-    static __forceinline vfloat4 load(const int8_t* ptr) {
+    static __forceinline vfloat4 load(const char* ptr) {
       return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
       return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
     }
     }
 #endif
 #endif
 
 
-#if defined(__aarch64__)
-    static __forceinline vfloat4 load(const uint8_t* ptr) {
-        return __m128(_mm_load4epu8_f32(((__m128i*)ptr)));
-    }
-#elif defined(__SSE4_1__)
-    static __forceinline vfloat4 load(const uint8_t* ptr) {
+#if defined(__SSE4_1__)
+    static __forceinline vfloat4 load(const unsigned char* ptr) {
       return _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
       return _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
     }
     }
 #else
 #else
-    static __forceinline vfloat4 load(const uint8_t* ptr) {
+    static __forceinline vfloat4 load(const unsigned char* ptr) {
       //return _mm_cvtpu8_ps(*(__m64*)ptr); // don't enable, will use MMX instructions
       //return _mm_cvtpu8_ps(*(__m64*)ptr); // don't enable, will use MMX instructions
       return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
       return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
     }
     }
 #endif
 #endif
 
 
-#if defined(__aarch64__)
-    static __forceinline vfloat4 load(const short* ptr) {
-        return __m128(_mm_load4epi16_f32(((__m128i*)ptr)));
-    }
-#elif defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     static __forceinline vfloat4 load(const short* ptr) {
     static __forceinline vfloat4 load(const short* ptr) {
       return _mm_cvtepi32_ps(_mm_cvtepi16_epi32(_mm_loadu_si128((__m128i*)ptr)));
       return _mm_cvtepi32_ps(_mm_cvtepi16_epi32(_mm_loadu_si128((__m128i*)ptr)));
     }
     }
@@ -157,15 +141,11 @@ namespace embree
     static __forceinline vfloat4 load(const unsigned short* ptr) {
     static __forceinline vfloat4 load(const unsigned short* ptr) {
       return _mm_mul_ps(vfloat4(vint4::load(ptr)),vfloat4(1.0f/65535.0f));
       return _mm_mul_ps(vfloat4(vint4::load(ptr)),vfloat4(1.0f/65535.0f));
     }
     }
-
+    
     static __forceinline void store_nt(void* ptr, const vfloat4& v)
     static __forceinline void store_nt(void* ptr, const vfloat4& v)
     {
     {
 #if defined (__SSE4_1__)
 #if defined (__SSE4_1__)
-#if defined(__aarch64__)
-      _mm_stream_ps((float*)ptr,vreinterpretq_s32_f32(v.v));
-#else
       _mm_stream_ps((float*)ptr,v);
       _mm_stream_ps((float*)ptr,v);
-#endif
 #else
 #else
       _mm_store_ps((float*)ptr,v);
       _mm_store_ps((float*)ptr,v);
 #endif
 #endif
@@ -173,14 +153,14 @@ namespace embree
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vfloat4 gather(const float* ptr, const vint4& index) {
     static __forceinline vfloat4 gather(const float* ptr, const vint4& index) {
-#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__AVX2__)
       return _mm_i32gather_ps(ptr, index, scale);
       return _mm_i32gather_ps(ptr, index, scale);
 #else
 #else
       return vfloat4(
       return vfloat4(
-        *(float*)(((int8_t*)ptr)+scale*index[0]),
-        *(float*)(((int8_t*)ptr)+scale*index[1]),
-        *(float*)(((int8_t*)ptr)+scale*index[2]),
-        *(float*)(((int8_t*)ptr)+scale*index[3]));
+        *(float*)(((char*)ptr)+scale*index[0]),
+        *(float*)(((char*)ptr)+scale*index[1]),
+        *(float*)(((char*)ptr)+scale*index[2]),
+        *(float*)(((char*)ptr)+scale*index[3]));
 #endif
 #endif
     }
     }
 
 
@@ -189,13 +169,13 @@ namespace embree
       vfloat4 r = zero;
       vfloat4 r = zero;
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       return _mm_mmask_i32gather_ps(r, mask, index, ptr, scale);
       return _mm_mmask_i32gather_ps(r, mask, index, ptr, scale);
-#elif defined(__AVX2__)  && !defined(__aarch64__)
+#elif defined(__AVX2__)
       return _mm_mask_i32gather_ps(r, ptr, index, mask, scale);
       return _mm_mask_i32gather_ps(r, ptr, index, mask, scale);
 #else
 #else
-      if (likely(mask[0])) r[0] = *(float*)(((int8_t*)ptr)+scale*index[0]);
-      if (likely(mask[1])) r[1] = *(float*)(((int8_t*)ptr)+scale*index[1]);
-      if (likely(mask[2])) r[2] = *(float*)(((int8_t*)ptr)+scale*index[2]);
-      if (likely(mask[3])) r[3] = *(float*)(((int8_t*)ptr)+scale*index[3]);
+      if (likely(mask[0])) r[0] = *(float*)(((char*)ptr)+scale*index[0]);
+      if (likely(mask[1])) r[1] = *(float*)(((char*)ptr)+scale*index[1]);
+      if (likely(mask[2])) r[2] = *(float*)(((char*)ptr)+scale*index[2]);
+      if (likely(mask[3])) r[3] = *(float*)(((char*)ptr)+scale*index[3]);
       return r;
       return r;
 #endif
 #endif
     }
     }
@@ -206,10 +186,10 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm_i32scatter_ps((float*)ptr, index, v, scale);
       _mm_i32scatter_ps((float*)ptr, index, v, scale);
 #else
 #else
-      *(float*)(((int8_t*)ptr)+scale*index[0]) = v[0];
-      *(float*)(((int8_t*)ptr)+scale*index[1]) = v[1];
-      *(float*)(((int8_t*)ptr)+scale*index[2]) = v[2];
-      *(float*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+      *(float*)(((char*)ptr)+scale*index[0]) = v[0];
+      *(float*)(((char*)ptr)+scale*index[1]) = v[1];
+      *(float*)(((char*)ptr)+scale*index[2]) = v[2];
+      *(float*)(((char*)ptr)+scale*index[3]) = v[3];
 #endif
 #endif
     }
     }
 
 
@@ -219,20 +199,20 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm_mask_i32scatter_ps((float*)ptr ,mask, index, v, scale);
       _mm_mask_i32scatter_ps((float*)ptr ,mask, index, v, scale);
 #else
 #else
-      if (likely(mask[0])) *(float*)(((int8_t*)ptr)+scale*index[0]) = v[0];
-      if (likely(mask[1])) *(float*)(((int8_t*)ptr)+scale*index[1]) = v[1];
-      if (likely(mask[2])) *(float*)(((int8_t*)ptr)+scale*index[2]) = v[2];
-      if (likely(mask[3])) *(float*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+      if (likely(mask[0])) *(float*)(((char*)ptr)+scale*index[0]) = v[0];
+      if (likely(mask[1])) *(float*)(((char*)ptr)+scale*index[1]) = v[1];
+      if (likely(mask[2])) *(float*)(((char*)ptr)+scale*index[2]) = v[2];
+      if (likely(mask[3])) *(float*)(((char*)ptr)+scale*index[3]) = v[3];
 #endif
 #endif
     }
     }
 
 
-    static __forceinline void store(const vboolf4& mask, int8_t* ptr, const vint4& ofs, const vfloat4& v) {
+    static __forceinline void store(const vboolf4& mask, char* ptr, const vint4& ofs, const vfloat4& v) {
       scatter<1>(mask,ptr,ofs,v);
       scatter<1>(mask,ptr,ofs,v);
     }
     }
     static __forceinline void store(const vboolf4& mask, float* ptr, const vint4& ofs, const vfloat4& v) {
     static __forceinline void store(const vboolf4& mask, float* ptr, const vint4& ofs, const vfloat4& v) {
       scatter<4>(mask,ptr,ofs,v);
       scatter<4>(mask,ptr,ofs,v);
     }
     }
-
+    
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -243,15 +223,27 @@ namespace embree
     friend __forceinline vfloat4 select(const vboolf4& m, const vfloat4& t, const vfloat4& f) {
     friend __forceinline vfloat4 select(const vboolf4& m, const vfloat4& t, const vfloat4& f) {
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       return _mm_mask_blend_ps(m, f, t);
       return _mm_mask_blend_ps(m, f, t);
-#elif defined(__SSE4_1__) || (defined(__aarch64__))
-      return _mm_blendv_ps(f, t, m);
+#elif defined(__SSE4_1__)
+      return _mm_blendv_ps(f, t, m); 
 #else
 #else
-      return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+      return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f)); 
 #endif
 #endif
     }
     }
   };
   };
 
 
+  ////////////////////////////////////////////////////////////////////////////////
+  /// Load/Store
+  ////////////////////////////////////////////////////////////////////////////////
 
 
+  template<> struct mem<vfloat4>
+  {
+    static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return vfloat4::load (mask,ptr); }
+    static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return vfloat4::loadu(mask,ptr); }
+    
+    static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { vfloat4::store (mask,ptr,v); }
+    static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { vfloat4::storeu(mask,ptr,v); }
+  };
+    
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Unary Operators
   /// Unary Operators
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -264,47 +256,18 @@ namespace embree
   __forceinline vfloat4 toFloat(const vint4&   a) { return vfloat4(a); }
   __forceinline vfloat4 toFloat(const vint4&   a) { return vfloat4(a); }
 
 
   __forceinline vfloat4 operator +(const vfloat4& a) { return a; }
   __forceinline vfloat4 operator +(const vfloat4& a) { return a; }
-#if defined(__aarch64__)
-  __forceinline vfloat4 operator -(const vfloat4& a) {
-    return vnegq_f32(a);
-  }
-#else
   __forceinline vfloat4 operator -(const vfloat4& a) { return _mm_xor_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
   __forceinline vfloat4 operator -(const vfloat4& a) { return _mm_xor_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
-#endif
 
 
-#if defined(__aarch64__)
-  __forceinline vfloat4 abs(const vfloat4& a) { return _mm_abs_ps(a); }
-#else
   __forceinline vfloat4 abs(const vfloat4& a) { return _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))); }
   __forceinline vfloat4 abs(const vfloat4& a) { return _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))); }
-#endif
-
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
   __forceinline vfloat4 sign(const vfloat4& a) { return _mm_mask_blend_ps(_mm_cmp_ps_mask(a, vfloat4(zero), _CMP_LT_OQ), vfloat4(one), -vfloat4(one)); }
   __forceinline vfloat4 sign(const vfloat4& a) { return _mm_mask_blend_ps(_mm_cmp_ps_mask(a, vfloat4(zero), _CMP_LT_OQ), vfloat4(one), -vfloat4(one)); }
 #else
 #else
   __forceinline vfloat4 sign(const vfloat4& a) { return blendv_ps(vfloat4(one), -vfloat4(one), _mm_cmplt_ps(a, vfloat4(zero))); }
   __forceinline vfloat4 sign(const vfloat4& a) { return blendv_ps(vfloat4(one), -vfloat4(one), _mm_cmplt_ps(a, vfloat4(zero))); }
 #endif
 #endif
-
-#if defined(__aarch64__)
-  __forceinline vfloat4 signmsk(const vfloat4& a) { return _mm_and_ps(a, vreinterpretq_f32_u32(v0x80000000)); }
-#else
   __forceinline vfloat4 signmsk(const vfloat4& a) { return _mm_and_ps(a,_mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
   __forceinline vfloat4 signmsk(const vfloat4& a) { return _mm_and_ps(a,_mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
-#endif
-
+  
   __forceinline vfloat4 rcp(const vfloat4& a)
   __forceinline vfloat4 rcp(const vfloat4& a)
   {
   {
-#if defined(__aarch64__)
-#if defined(BUILD_IOS)
-    return vfloat4(vdivq_f32(vdupq_n_f32(1.0f),a.v));
-#else //BUILD_IOS
-    __m128 reciprocal = _mm_rcp_ps(a);
-    reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
-    reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
-    // +1 round since NEON's reciprocal estimate instruction has less accuracy than SSE2's rcp.
-    reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
-    return (const vfloat4)reciprocal;
-#endif // BUILD_IOS
-#else
-
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     const vfloat4 r = _mm_rcp14_ps(a);
     const vfloat4 r = _mm_rcp14_ps(a);
 #else
 #else
@@ -316,45 +279,31 @@ namespace embree
 #else
 #else
     return _mm_mul_ps(r,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r, a)));
     return _mm_mul_ps(r,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r, a)));
 #endif
 #endif
-
-#endif  //defined(__aarch64__)
   }
   }
   __forceinline vfloat4 sqr (const vfloat4& a) { return _mm_mul_ps(a,a); }
   __forceinline vfloat4 sqr (const vfloat4& a) { return _mm_mul_ps(a,a); }
   __forceinline vfloat4 sqrt(const vfloat4& a) { return _mm_sqrt_ps(a); }
   __forceinline vfloat4 sqrt(const vfloat4& a) { return _mm_sqrt_ps(a); }
 
 
   __forceinline vfloat4 rsqrt(const vfloat4& a)
   __forceinline vfloat4 rsqrt(const vfloat4& a)
   {
   {
-#if defined(__aarch64__)
-    vfloat4 r = _mm_rsqrt_ps(a);
-    r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a, r), r));
-    r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a, r), r));
-    r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a, r), r));
-    return r;
-#else
-
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
-    const vfloat4 r = _mm_rsqrt14_ps(a);
+    vfloat4 r = _mm_rsqrt14_ps(a);
 #else
 #else
-    const vfloat4 r = _mm_rsqrt_ps(a);
+    vfloat4 r = _mm_rsqrt_ps(a);
 #endif
 #endif
 
 
-#if defined(__AVX2__)
-    return _mm_fmadd_ps(_mm_set1_ps(1.5f), r,
-                        _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#if defined(__ARM_NEON)
+    r = _mm_fmadd_ps(_mm_set1_ps(1.5f), r, _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+    r = _mm_fmadd_ps(_mm_set1_ps(1.5f), r, _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#elif defined(__AVX2__)
+    r = _mm_fmadd_ps(_mm_set1_ps(1.5f), r, _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
 #else
 #else
-    return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r),
-                      _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
-#endif
-
+    r = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
 #endif
 #endif
+    return r;
   }
   }
 
 
   __forceinline vboolf4 isnan(const vfloat4& a) {
   __forceinline vboolf4 isnan(const vfloat4& a) {
-#if defined(__aarch64__)
-    const vfloat4 b = _mm_and_ps(a, vreinterpretq_f32_u32(v0x7fffffff));
-#else
     const vfloat4 b = _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
     const vfloat4 b = _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
-#endif
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     return _mm_cmp_epi32_mask(_mm_castps_si128(b), _mm_set1_epi32(0x7f800000), _MM_CMPINT_GT);
     return _mm_cmp_epi32_mask(_mm_castps_si128(b), _mm_set1_epi32(0x7f800000), _MM_CMPINT_GT);
 #else
 #else
@@ -395,8 +344,7 @@ namespace embree
   __forceinline vfloat4 max(const vfloat4& a, float          b) { return _mm_max_ps(a,vfloat4(b)); }
   __forceinline vfloat4 max(const vfloat4& a, float          b) { return _mm_max_ps(a,vfloat4(b)); }
   __forceinline vfloat4 max(float          a, const vfloat4& b) { return _mm_max_ps(vfloat4(a),b); }
   __forceinline vfloat4 max(float          a, const vfloat4& b) { return _mm_max_ps(vfloat4(a),b); }
 
 
-#if defined(__SSE4_1__) || defined(__aarch64__)
-
+#if defined(__SSE4_1__)
     __forceinline vfloat4 mini(const vfloat4& a, const vfloat4& b) {
     __forceinline vfloat4 mini(const vfloat4& a, const vfloat4& b) {
       const vint4 ai = _mm_castps_si128(a);
       const vint4 ai = _mm_castps_si128(a);
       const vint4 bi = _mm_castps_si128(b);
       const vint4 bi = _mm_castps_si128(b);
@@ -438,30 +386,16 @@ namespace embree
   /// Ternary Operators
   /// Ternary Operators
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined(__AVX2__)
+#if defined(__AVX2__) || defined(__ARM_NEON)
   __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmadd_ps(a,b,c); }
   __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmadd_ps(a,b,c); }
   __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmsub_ps(a,b,c); }
   __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmsub_ps(a,b,c); }
   __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmadd_ps(a,b,c); }
   __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmadd_ps(a,b,c); }
   __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmsub_ps(a,b,c); }
   __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmsub_ps(a,b,c); }
 #else
 #else
-
-#if defined(__aarch64__)
-  __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) {
-    return _mm_madd_ps(a, b, c);  //a*b+c;
-  }
-  __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) {
-    return _mm_msub_ps(a, b, c);  //-a*b+c;
-  }
-  __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) {
-    return vnegq_f32(vfmaq_f32(c,a, b));
-  }
-#else
   __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b+c; }
   __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b+c; }
+  __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b-c; }
   __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b+c;}
   __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b+c;}
   __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b-c; }
   __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b-c; }
-#endif
-  __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b-c; }
-
 #endif
 #endif
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -495,13 +429,8 @@ namespace embree
   __forceinline vboolf4 operator ==(const vfloat4& a, const vfloat4& b) { return _mm_cmpeq_ps (a, b); }
   __forceinline vboolf4 operator ==(const vfloat4& a, const vfloat4& b) { return _mm_cmpeq_ps (a, b); }
   __forceinline vboolf4 operator !=(const vfloat4& a, const vfloat4& b) { return _mm_cmpneq_ps(a, b); }
   __forceinline vboolf4 operator !=(const vfloat4& a, const vfloat4& b) { return _mm_cmpneq_ps(a, b); }
   __forceinline vboolf4 operator < (const vfloat4& a, const vfloat4& b) { return _mm_cmplt_ps (a, b); }
   __forceinline vboolf4 operator < (const vfloat4& a, const vfloat4& b) { return _mm_cmplt_ps (a, b); }
-#if defined(__aarch64__)
-  __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmpge_ps (a, b); }
-  __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmpgt_ps (a, b); }
-#else
   __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmpnlt_ps(a, b); }
   __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmpnlt_ps(a, b); }
   __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmpnle_ps(a, b); }
   __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmpnle_ps(a, b); }
-#endif
   __forceinline vboolf4 operator <=(const vfloat4& a, const vfloat4& b) { return _mm_cmple_ps (a, b); }
   __forceinline vboolf4 operator <=(const vfloat4& a, const vfloat4& b) { return _mm_cmple_ps (a, b); }
 #endif
 #endif
 
 
@@ -513,7 +442,7 @@ namespace embree
 
 
   __forceinline vboolf4 operator < (const vfloat4& a, float          b) { return a <  vfloat4(b); }
   __forceinline vboolf4 operator < (const vfloat4& a, float          b) { return a <  vfloat4(b); }
   __forceinline vboolf4 operator < (float          a, const vfloat4& b) { return vfloat4(a) <  b; }
   __forceinline vboolf4 operator < (float          a, const vfloat4& b) { return vfloat4(a) <  b; }
-
+  
   __forceinline vboolf4 operator >=(const vfloat4& a, float          b) { return a >= vfloat4(b); }
   __forceinline vboolf4 operator >=(const vfloat4& a, float          b) { return a >= vfloat4(b); }
   __forceinline vboolf4 operator >=(float          a, const vfloat4& b) { return vfloat4(a) >= b; }
   __forceinline vboolf4 operator >=(float          a, const vfloat4& b) { return vfloat4(a) >= b; }
 
 
@@ -549,68 +478,17 @@ namespace embree
   template<int mask>
   template<int mask>
     __forceinline vfloat4 select(const vfloat4& t, const vfloat4& f)
     __forceinline vfloat4 select(const vfloat4& t, const vfloat4& f)
   {
   {
-#if defined(__SSE4_1__)
+#if defined(__SSE4_1__) 
     return _mm_blend_ps(f, t, mask);
     return _mm_blend_ps(f, t, mask);
 #else
 #else
     return select(vboolf4(mask), t, f);
     return select(vboolf4(mask), t, f);
 #endif
 #endif
   }
   }
-
-#if defined(__aarch64__)
-    template<> __forceinline vfloat4 select<0>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vzero));
-    }
-    template<> __forceinline vfloat4 select<1>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v000F));
-    }
-    template<> __forceinline vfloat4 select<2>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v00F0));
-    }
-    template<> __forceinline vfloat4 select<3>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v00FF));
-    }
-    template<> __forceinline vfloat4 select<4>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0F00));
-    }
-    template<> __forceinline vfloat4 select<5>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0F0F));
-    }
-    template<> __forceinline vfloat4 select<6>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0FF0));
-    }
-    template<> __forceinline vfloat4 select<7>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0FFF));
-    }
-    template<> __forceinline vfloat4 select<8>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF000));
-    }
-    template<> __forceinline vfloat4 select<9>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF00F));
-    }
-    template<> __forceinline vfloat4 select<10>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF0F0));
-    }
-    template<> __forceinline vfloat4 select<11>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF0FF));
-    }
-    template<> __forceinline vfloat4 select<12>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFF00));
-    }
-    template<> __forceinline vfloat4 select<13>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFF0F));
-    }
-    template<> __forceinline vfloat4 select<14>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFFF0));
-    }
-    template<> __forceinline vfloat4 select<15>(const vfloat4& t, const vfloat4& f) {
-        return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFFFF));
-    }
-#endif
-
+  
   __forceinline vfloat4 lerp(const vfloat4& a, const vfloat4& b, const vfloat4& t) {
   __forceinline vfloat4 lerp(const vfloat4& a, const vfloat4& b, const vfloat4& t) {
     return madd(t,b-a,a);
     return madd(t,b-a,a);
   }
   }
-
+  
   __forceinline bool isvalid(const vfloat4& v) {
   __forceinline bool isvalid(const vfloat4& v) {
     return all((v > vfloat4(-FLT_LARGE)) & (v < vfloat4(+FLT_LARGE)));
     return all((v > vfloat4(-FLT_LARGE)) & (v < vfloat4(+FLT_LARGE)));
   }
   }
@@ -622,21 +500,21 @@ namespace embree
   __forceinline bool is_finite(const vboolf4& valid, const vfloat4& a) {
   __forceinline bool is_finite(const vboolf4& valid, const vfloat4& a) {
     return all(valid, (a >= vfloat4(-FLT_MAX)) & (a <= vfloat4(+FLT_MAX)));
     return all(valid, (a >= vfloat4(-FLT_MAX)) & (a <= vfloat4(+FLT_MAX)));
   }
   }
-
+  
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Rounding Functions
   /// Rounding Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
 #if defined(__aarch64__)
 #if defined(__aarch64__)
-  __forceinline vfloat4 floor(const vfloat4& a) { return vrndmq_f32(a.v); } // towards -inf
-  __forceinline vfloat4 ceil (const vfloat4& a) { return vrndpq_f32(a.v); } // toward +inf
-  __forceinline vfloat4 trunc(const vfloat4& a) { return vrndq_f32(a.v); } // towards 0
-  __forceinline vfloat4 round(const vfloat4& a) { return vrndnq_f32(a.v); } // to nearest, ties to even. NOTE(LTE): arm clang uses vrndnq, old gcc uses vrndqn?
+  __forceinline vfloat4 floor(const vfloat4& a) { return vrndmq_f32(a.v); }
+  __forceinline vfloat4 ceil (const vfloat4& a) { return vrndpq_f32(a.v); }
+  __forceinline vfloat4 trunc(const vfloat4& a) { return vrndq_f32(a.v); }
+  __forceinline vfloat4 round(const vfloat4& a) { return vrndnq_f32(a.v); }
 #elif defined (__SSE4_1__)
 #elif defined (__SSE4_1__)
-  __forceinline vfloat4 floor(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF   ); }
-  __forceinline vfloat4 ceil (const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF   ); }
-  __forceinline vfloat4 trunc(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_ZERO      ); }
-  __forceinline vfloat4 round(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); } // (even) https://www.felixcloutier.com/x86/roundpd
+  __forceinline vfloat4 floor(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF    ); }
+  __forceinline vfloat4 ceil (const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF    ); }
+  __forceinline vfloat4 trunc(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_ZERO       ); }
+  __forceinline vfloat4 round(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
 #else
 #else
   __forceinline vfloat4 floor(const vfloat4& a) { return vfloat4(floorf(a[0]),floorf(a[1]),floorf(a[2]),floorf(a[3])); }
   __forceinline vfloat4 floor(const vfloat4& a) { return vfloat4(floorf(a[0]),floorf(a[1]),floorf(a[2]),floorf(a[3])); }
   __forceinline vfloat4 ceil (const vfloat4& a) { return vfloat4(ceilf (a[0]),ceilf (a[1]),ceilf (a[2]),ceilf (a[3])); }
   __forceinline vfloat4 ceil (const vfloat4& a) { return vfloat4(ceilf (a[0]),ceilf (a[1]),ceilf (a[2]),ceilf (a[3])); }
@@ -646,9 +524,7 @@ namespace embree
   __forceinline vfloat4 frac(const vfloat4& a) { return a-floor(a); }
   __forceinline vfloat4 frac(const vfloat4& a) { return a-floor(a); }
 
 
   __forceinline vint4 floori(const vfloat4& a) {
   __forceinline vint4 floori(const vfloat4& a) {
-#if defined(__aarch64__)
-    return vcvtq_s32_f32(floor(a));
-#elif defined(__SSE4_1__)
+#if defined(__SSE4_1__)
     return vint4(floor(a));
     return vint4(floor(a));
 #else
 #else
     return vint4(a-vfloat4(0.5f));
     return vint4(a-vfloat4(0.5f));
@@ -662,16 +538,6 @@ namespace embree
   __forceinline vfloat4 unpacklo(const vfloat4& a, const vfloat4& b) { return _mm_unpacklo_ps(a, b); }
   __forceinline vfloat4 unpacklo(const vfloat4& a, const vfloat4& b) { return _mm_unpacklo_ps(a, b); }
   __forceinline vfloat4 unpackhi(const vfloat4& a, const vfloat4& b) { return _mm_unpackhi_ps(a, b); }
   __forceinline vfloat4 unpackhi(const vfloat4& a, const vfloat4& b) { return _mm_unpackhi_ps(a, b); }
 
 
-#if defined(__aarch64__)
-      template<int i0, int i1, int i2, int i3>
-      __forceinline vfloat4 shuffle(const vfloat4& v) {
-          return vreinterpretq_f32_u8(vqtbl1q_u8( (uint8x16_t)v.v, _MN_SHUFFLE(i0, i1, i2, i3)));
-      }
-      template<int i0, int i1, int i2, int i3>
-      __forceinline vfloat4 shuffle(const vfloat4& a, const vfloat4& b) {
-          return vreinterpretq_f32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
-      }
-#else
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
   __forceinline vfloat4 shuffle(const vfloat4& v) {
   __forceinline vfloat4 shuffle(const vfloat4& v) {
     return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v), _MM_SHUFFLE(i3, i2, i1, i0)));
     return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v), _MM_SHUFFLE(i3, i2, i1, i0)));
@@ -681,19 +547,8 @@ namespace embree
   __forceinline vfloat4 shuffle(const vfloat4& a, const vfloat4& b) {
   __forceinline vfloat4 shuffle(const vfloat4& a, const vfloat4& b) {
     return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
     return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
   }
   }
-#endif
-
-#if defined (__SSSE3__)
-  __forceinline vfloat4 shuffle8(const vfloat4& a, const vint4& shuf) {
-    return _mm_castsi128_ps(_mm_shuffle_epi8(_mm_castps_si128(a), shuf));
-  }
-#endif
 
 
-#if defined(__aarch64__) 
-  template<> __forceinline vfloat4 shuffle<0, 0, 2, 2>(const vfloat4& v) { return __m128(vqtbl1q_u8( uint8x16_t(v.v), v0022 )); }
-  template<> __forceinline vfloat4 shuffle<1, 1, 3, 3>(const vfloat4& v) { return __m128(vqtbl1q_u8( uint8x16_t(v.v), v1133)); }
-  template<> __forceinline vfloat4 shuffle<0, 1, 0, 1>(const vfloat4& v) { return __m128(vqtbl1q_u8( uint8x16_t(v.v), v0101)); }
-#elif defined(__SSE3__)
+#if defined(__SSE3__)
   template<> __forceinline vfloat4 shuffle<0, 0, 2, 2>(const vfloat4& v) { return _mm_moveldup_ps(v); }
   template<> __forceinline vfloat4 shuffle<0, 0, 2, 2>(const vfloat4& v) { return _mm_moveldup_ps(v); }
   template<> __forceinline vfloat4 shuffle<1, 1, 3, 3>(const vfloat4& v) { return _mm_movehdup_ps(v); }
   template<> __forceinline vfloat4 shuffle<1, 1, 3, 3>(const vfloat4& v) { return _mm_movehdup_ps(v); }
   template<> __forceinline vfloat4 shuffle<0, 1, 0, 1>(const vfloat4& v) { return _mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(v))); }
   template<> __forceinline vfloat4 shuffle<0, 1, 0, 1>(const vfloat4& v) { return _mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(v))); }
@@ -704,56 +559,10 @@ namespace embree
     return shuffle<i,i,i,i>(v);
     return shuffle<i,i,i,i>(v);
   }
   }
 
 
-#if defined(__aarch64__)
-  template<int i> __forceinline float extract(const vfloat4& a);
-  template<> __forceinline float extract<0>(const vfloat4& b) {
-      return b[0];
-  }
-  template<> __forceinline float extract<1>(const vfloat4& b) {
-      return b[1];
-  }
-  template<> __forceinline float extract<2>(const vfloat4& b) {
-      return b[2];
-  }
-  template<> __forceinline float extract<3>(const vfloat4& b) {
-      return b[3];
-  }
-#elif defined (__SSE4_1__) && !defined(__GNUC__)
-  template<int i> __forceinline float extract(const vfloat4& a) { return _mm_cvtss_f32(_mm_extract_ps(a,i)); }
-  template<> __forceinline float extract<0>(const vfloat4& a) { return _mm_cvtss_f32(a); }
-#else
-  template<int i> __forceinline float extract(const vfloat4& a) { return _mm_cvtss_f32(shuffle<i,i,i,i>(a)); }
-  template<> __forceinline float extract<0>(const vfloat4& a) { return _mm_cvtss_f32(a); }
-#endif
-
+  template<int i> __forceinline float extract   (const vfloat4& a) { return _mm_cvtss_f32(shuffle<i>(a)); }
+  template<>      __forceinline float extract<0>(const vfloat4& a) { return _mm_cvtss_f32(a); }
 
 
-#if defined(__aarch64__)
-  template<int dst>  __forceinline vfloat4 insert(const vfloat4& a, float b);
-  template<> __forceinline vfloat4 insert<0>(const vfloat4& a, float b)
-  {
-        vfloat4 c = a;
-        c[0] = b;
-        return c;
-  }
-  template<> __forceinline vfloat4 insert<1>(const vfloat4& a, float b)
-  {
-        vfloat4 c = a;
-        c[1] = b;
-        return c;
-  }
-  template<> __forceinline vfloat4 insert<2>(const vfloat4& a, float b)
-  {
-        vfloat4 c = a;
-        c[2] = b;
-        return c;
-  }
-  template<> __forceinline vfloat4 insert<3>(const vfloat4& a, float b)
-  {
-        vfloat4 c = a;
-        c[3] = b;
-        return c;
-  }
-#elif defined (__SSE4_1__)
+#if defined (__SSE4_1__)
   template<int dst, int src, int clr> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
   template<int dst, int src, int clr> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
   template<int dst, int src> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return insert<dst, src, 0>(a, b); }
   template<int dst, int src> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return insert<dst, src, 0>(a, b); }
   template<int dst> __forceinline vfloat4 insert(const vfloat4& a, const float b) { return insert<dst, 0>(a, _mm_set_ss(b)); }
   template<int dst> __forceinline vfloat4 insert(const vfloat4& a, const float b) { return insert<dst, 0>(a, _mm_set_ss(b)); }
@@ -762,19 +571,10 @@ namespace embree
   template<int dst>  __forceinline vfloat4 insert(const vfloat4& a, float b) { vfloat4 c = a; c[dst&3] = b; return c; }
   template<int dst>  __forceinline vfloat4 insert(const vfloat4& a, float b) { vfloat4 c = a; c[dst&3] = b; return c; }
 #endif
 #endif
 
 
-#if defined(__aarch64__)
-  __forceinline float toScalar(const vfloat4& v) {
-    return v[0];
-  }
-#else
   __forceinline float toScalar(const vfloat4& v) { return _mm_cvtss_f32(v); }
   __forceinline float toScalar(const vfloat4& v) { return _mm_cvtss_f32(v); }
-#endif
-  __forceinline vfloat4 broadcast4f(const vfloat4& a, size_t k) {
-    return vfloat4::broadcast(&a[k]);
-  }
 
 
   __forceinline vfloat4 shift_right_1(const vfloat4& x) {
   __forceinline vfloat4 shift_right_1(const vfloat4& x) {
-    return _mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(x), 4));
+    return _mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(x), 4)); 
   }
   }
 
 
 #if defined (__AVX2__)
 #if defined (__AVX2__)
@@ -790,7 +590,7 @@ namespace embree
   template<int i>
   template<int i>
   __forceinline vfloat4 align_shift_right(const vfloat4& a, const vfloat4& b) {
   __forceinline vfloat4 align_shift_right(const vfloat4& a, const vfloat4& b) {
     return _mm_castsi128_ps(_mm_alignr_epi32(_mm_castps_si128(a), _mm_castps_si128(b), i));
     return _mm_castsi128_ps(_mm_alignr_epi32(_mm_castps_si128(a), _mm_castps_si128(b), i));
-  }
+  }  
 #endif
 #endif
 
 
 
 
@@ -864,39 +664,28 @@ namespace embree
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
-#if defined(__aarch64__)
-      __forceinline vfloat4 vreduce_min(const vfloat4& v) { float h = vminvq_f32(v); return vdupq_n_f32(h); }
-      __forceinline vfloat4 vreduce_max(const vfloat4& v) { float h = vmaxvq_f32(v); return vdupq_n_f32(h); }
-      __forceinline vfloat4 vreduce_add(const vfloat4& v) { float h = vaddvq_f32(v); return vdupq_n_f32(h); }
-#else
+
   __forceinline vfloat4 vreduce_min(const vfloat4& v) { vfloat4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
   __forceinline vfloat4 vreduce_min(const vfloat4& v) { vfloat4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
   __forceinline vfloat4 vreduce_max(const vfloat4& v) { vfloat4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
   __forceinline vfloat4 vreduce_max(const vfloat4& v) { vfloat4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
   __forceinline vfloat4 vreduce_add(const vfloat4& v) { vfloat4 h = shuffle<1,0,3,2>(v)   + v ; return shuffle<2,3,0,1>(h)   + h ; }
   __forceinline vfloat4 vreduce_add(const vfloat4& v) { vfloat4 h = shuffle<1,0,3,2>(v)   + v ; return shuffle<2,3,0,1>(h)   + h ; }
-#endif
 
 
-#if defined(__aarch64__)
-  __forceinline float reduce_min(const vfloat4& v) { return vminvq_f32(v); }
-  __forceinline float reduce_max(const vfloat4& v) { return vmaxvq_f32(v); }
-  __forceinline float reduce_add(const vfloat4& v) { return vaddvq_f32(v); }
-#else
   __forceinline float reduce_min(const vfloat4& v) { return _mm_cvtss_f32(vreduce_min(v)); }
   __forceinline float reduce_min(const vfloat4& v) { return _mm_cvtss_f32(vreduce_min(v)); }
   __forceinline float reduce_max(const vfloat4& v) { return _mm_cvtss_f32(vreduce_max(v)); }
   __forceinline float reduce_max(const vfloat4& v) { return _mm_cvtss_f32(vreduce_max(v)); }
   __forceinline float reduce_add(const vfloat4& v) { return _mm_cvtss_f32(vreduce_add(v)); }
   __forceinline float reduce_add(const vfloat4& v) { return _mm_cvtss_f32(vreduce_add(v)); }
-#endif
 
 
-  __forceinline size_t select_min(const vboolf4& valid, const vfloat4& v)
-  {
-    const vfloat4 a = select(valid,v,vfloat4(pos_inf));
+  __forceinline size_t select_min(const vboolf4& valid, const vfloat4& v) 
+  { 
+    const vfloat4 a = select(valid,v,vfloat4(pos_inf)); 
     const vbool4 valid_min = valid & (a == vreduce_min(a));
     const vbool4 valid_min = valid & (a == vreduce_min(a));
-    return bsf(movemask(any(valid_min) ? valid_min : valid));
+    return bsf(movemask(any(valid_min) ? valid_min : valid)); 
   }
   }
-  __forceinline size_t select_max(const vboolf4& valid, const vfloat4& v)
-  {
-    const vfloat4 a = select(valid,v,vfloat4(neg_inf));
+  __forceinline size_t select_max(const vboolf4& valid, const vfloat4& v) 
+  { 
+    const vfloat4 a = select(valid,v,vfloat4(neg_inf)); 
     const vbool4 valid_max = valid & (a == vreduce_max(a));
     const vbool4 valid_max = valid & (a == vreduce_max(a));
-    return bsf(movemask(any(valid_max) ? valid_max : valid));
+    return bsf(movemask(any(valid_max) ? valid_max : valid)); 
   }
   }
-
+  
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Euclidian Space Operators
   /// Euclidian Space Operators
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -911,7 +700,7 @@ namespace embree
     const vfloat4 b0 = shuffle<1,2,0,3>(b);
     const vfloat4 b0 = shuffle<1,2,0,3>(b);
     const vfloat4 a1 = shuffle<1,2,0,3>(a);
     const vfloat4 a1 = shuffle<1,2,0,3>(a);
     const vfloat4 b1 = b;
     const vfloat4 b1 = b;
-    return shuffle<1,2,0,3>(prod_diff(a0,b0,a1,b1));
+    return shuffle<1,2,0,3>(msub(a0,b0,a1*b1));
   }
   }
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -923,3 +712,11 @@ namespace embree
   }
   }
 
 
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 71 - 160
thirdparty/embree-aarch64/common/simd/vfloat8_avx.h → thirdparty/embree/common/simd/vfloat8_avx.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX float type */
   /* 8-wide AVX float type */
@@ -33,7 +41,7 @@ namespace embree
     __forceinline explicit vfloat(const vfloat4& a) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),a,1)) {}
     __forceinline explicit vfloat(const vfloat4& a) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),a,1)) {}
     __forceinline vfloat(const vfloat4& a, const vfloat4& b) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),b,1)) {}
     __forceinline vfloat(const vfloat4& a, const vfloat4& b) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),b,1)) {}
 
 
-    __forceinline explicit vfloat(const int8_t* a) : v(_mm256_loadu_ps((const float*)a)) {}
+    __forceinline explicit vfloat(const char* a) : v(_mm256_loadu_ps((const float*)a)) {}
     __forceinline vfloat(float a) : v(_mm256_set1_ps(a)) {}
     __forceinline vfloat(float a) : v(_mm256_set1_ps(a)) {}
     __forceinline vfloat(float a, float b) : v(_mm256_set_ps(b, a, b, a, b, a, b, a)) {}
     __forceinline vfloat(float a, float b) : v(_mm256_set_ps(b, a, b, a, b, a, b, a)) {}
     __forceinline vfloat(float a, float b, float c, float d) : v(_mm256_set_ps(d, c, b, a, d, c, b, a)) {}
     __forceinline vfloat(float a, float b, float c, float d) : v(_mm256_set_ps(d, c, b, a, d, c, b, a)) {}
@@ -61,21 +69,7 @@ namespace embree
       return _mm256_broadcast_ss((float*)a); 
       return _mm256_broadcast_ss((float*)a); 
     }
     }
 
 
-    static __forceinline vfloat8 broadcast2(const float* a, const float* b) {
-#if defined(__INTEL_COMPILER)
-      const vfloat8 v0 = _mm256_broadcast_ss(a); 
-      const vfloat8 v1 = _mm256_broadcast_ss(b); 
-      return _mm256_blend_ps(v1, v0, 0xf);
-#else
-      return _mm256_set_ps(*b,*b,*b,*b,*a,*a,*a,*a);
-#endif
-    }
-
-    static __forceinline vfloat8 broadcast4f(const vfloat4* ptr) {
-      return _mm256_broadcast_ps((__m128*)ptr); 
-    }
-
-    static __forceinline vfloat8 load(const int8_t* ptr) {
+    static __forceinline vfloat8 load(const char* ptr) {
 #if defined(__AVX2__)
 #if defined(__AVX2__)
       return _mm256_cvtepi32_ps(_mm256_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
       return _mm256_cvtepi32_ps(_mm256_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
 #else
 #else
@@ -83,7 +77,7 @@ namespace embree
 #endif
 #endif
     }
     }
 
 
-    static __forceinline vfloat8 load(const uint8_t* ptr) {
+    static __forceinline vfloat8 load(const unsigned char* ptr) {
 #if defined(__AVX2__)
 #if defined(__AVX2__)
       return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
       return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
 #else
 #else
@@ -107,24 +101,11 @@ namespace embree
 
 
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
 
 
-    static __forceinline vfloat8 compact(const vboolf8& mask, vfloat8 &v) {
-      return _mm256_mask_compress_ps(v, mask, v);
-    }
-    static __forceinline vfloat8 compact(const vboolf8& mask, vfloat8 &a, const vfloat8& b) {
-      return _mm256_mask_compress_ps(a, mask, b);
-    }
-
     static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_ps (_mm256_setzero_ps(),mask,(float*)ptr); }
     static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_ps (_mm256_setzero_ps(),mask,(float*)ptr); }
     static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_ps(_mm256_setzero_ps(),mask,(float*)ptr); }
     static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_ps(_mm256_setzero_ps(),mask,(float*)ptr); }
 
 
     static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_store_ps ((float*)ptr,mask,v); }
     static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_store_ps ((float*)ptr,mask,v); }
     static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_storeu_ps((float*)ptr,mask,v); }
     static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_storeu_ps((float*)ptr,mask,v); }
-#elif defined(__aarch64__)
-    static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask.v); }
-    static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask.v); }
-
-    static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,v); }
-    static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,v); }
 #else
 #else
     static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
     static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
     static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
     static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
@@ -145,18 +126,18 @@ namespace embree
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vfloat8 gather(const float* ptr, const vint8& index) {
     static __forceinline vfloat8 gather(const float* ptr, const vint8& index) {
-#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__AVX2__)
       return _mm256_i32gather_ps(ptr, index ,scale);
       return _mm256_i32gather_ps(ptr, index ,scale);
 #else
 #else
       return vfloat8(
       return vfloat8(
-          *(float*)(((int8_t*)ptr)+scale*index[0]),
-          *(float*)(((int8_t*)ptr)+scale*index[1]),
-          *(float*)(((int8_t*)ptr)+scale*index[2]),
-          *(float*)(((int8_t*)ptr)+scale*index[3]),
-          *(float*)(((int8_t*)ptr)+scale*index[4]),
-          *(float*)(((int8_t*)ptr)+scale*index[5]),
-          *(float*)(((int8_t*)ptr)+scale*index[6]),
-          *(float*)(((int8_t*)ptr)+scale*index[7]));
+          *(float*)(((char*)ptr)+scale*index[0]),
+          *(float*)(((char*)ptr)+scale*index[1]),
+          *(float*)(((char*)ptr)+scale*index[2]),
+          *(float*)(((char*)ptr)+scale*index[3]),
+          *(float*)(((char*)ptr)+scale*index[4]),
+          *(float*)(((char*)ptr)+scale*index[5]),
+          *(float*)(((char*)ptr)+scale*index[6]),
+          *(float*)(((char*)ptr)+scale*index[7]));
 #endif
 #endif
     }
     }
 
 
@@ -165,17 +146,17 @@ namespace embree
       vfloat8 r = zero;
       vfloat8 r = zero;
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       return _mm256_mmask_i32gather_ps(r, mask, index, ptr, scale);
       return _mm256_mmask_i32gather_ps(r, mask, index, ptr, scale);
-#elif defined(__AVX2__) && !defined(__aarch64__)
+#elif defined(__AVX2__)
       return _mm256_mask_i32gather_ps(r, ptr, index, mask, scale);
       return _mm256_mask_i32gather_ps(r, ptr, index, mask, scale);
 #else
 #else
-      if (likely(mask[0])) r[0] = *(float*)(((int8_t*)ptr)+scale*index[0]);
-      if (likely(mask[1])) r[1] = *(float*)(((int8_t*)ptr)+scale*index[1]);
-      if (likely(mask[2])) r[2] = *(float*)(((int8_t*)ptr)+scale*index[2]);
-      if (likely(mask[3])) r[3] = *(float*)(((int8_t*)ptr)+scale*index[3]);
-      if (likely(mask[4])) r[4] = *(float*)(((int8_t*)ptr)+scale*index[4]);
-      if (likely(mask[5])) r[5] = *(float*)(((int8_t*)ptr)+scale*index[5]);
-      if (likely(mask[6])) r[6] = *(float*)(((int8_t*)ptr)+scale*index[6]);
-      if (likely(mask[7])) r[7] = *(float*)(((int8_t*)ptr)+scale*index[7]);
+      if (likely(mask[0])) r[0] = *(float*)(((char*)ptr)+scale*index[0]);
+      if (likely(mask[1])) r[1] = *(float*)(((char*)ptr)+scale*index[1]);
+      if (likely(mask[2])) r[2] = *(float*)(((char*)ptr)+scale*index[2]);
+      if (likely(mask[3])) r[3] = *(float*)(((char*)ptr)+scale*index[3]);
+      if (likely(mask[4])) r[4] = *(float*)(((char*)ptr)+scale*index[4]);
+      if (likely(mask[5])) r[5] = *(float*)(((char*)ptr)+scale*index[5]);
+      if (likely(mask[6])) r[6] = *(float*)(((char*)ptr)+scale*index[6]);
+      if (likely(mask[7])) r[7] = *(float*)(((char*)ptr)+scale*index[7]);
       return r;
       return r;
     #endif
     #endif
     }
     }
@@ -186,14 +167,14 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm256_i32scatter_ps((float*)ptr, ofs, v, scale);
       _mm256_i32scatter_ps((float*)ptr, ofs, v, scale);
 #else
 #else
-      *(float*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
-      *(float*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
-      *(float*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
-      *(float*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
-      *(float*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
-      *(float*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
-      *(float*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
-      *(float*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+      *(float*)(((char*)ptr)+scale*ofs[0]) = v[0];
+      *(float*)(((char*)ptr)+scale*ofs[1]) = v[1];
+      *(float*)(((char*)ptr)+scale*ofs[2]) = v[2];
+      *(float*)(((char*)ptr)+scale*ofs[3]) = v[3];
+      *(float*)(((char*)ptr)+scale*ofs[4]) = v[4];
+      *(float*)(((char*)ptr)+scale*ofs[5]) = v[5];
+      *(float*)(((char*)ptr)+scale*ofs[6]) = v[6];
+      *(float*)(((char*)ptr)+scale*ofs[7]) = v[7];
 #endif
 #endif
     }
     }
 
 
@@ -203,24 +184,17 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm256_mask_i32scatter_ps((float*)ptr, mask, ofs, v, scale);
       _mm256_mask_i32scatter_ps((float*)ptr, mask, ofs, v, scale);
 #else
 #else
-      if (likely(mask[0])) *(float*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
-      if (likely(mask[1])) *(float*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
-      if (likely(mask[2])) *(float*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
-      if (likely(mask[3])) *(float*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
-      if (likely(mask[4])) *(float*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
-      if (likely(mask[5])) *(float*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
-      if (likely(mask[6])) *(float*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
-      if (likely(mask[7])) *(float*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+      if (likely(mask[0])) *(float*)(((char*)ptr)+scale*ofs[0]) = v[0];
+      if (likely(mask[1])) *(float*)(((char*)ptr)+scale*ofs[1]) = v[1];
+      if (likely(mask[2])) *(float*)(((char*)ptr)+scale*ofs[2]) = v[2];
+      if (likely(mask[3])) *(float*)(((char*)ptr)+scale*ofs[3]) = v[3];
+      if (likely(mask[4])) *(float*)(((char*)ptr)+scale*ofs[4]) = v[4];
+      if (likely(mask[5])) *(float*)(((char*)ptr)+scale*ofs[5]) = v[5];
+      if (likely(mask[6])) *(float*)(((char*)ptr)+scale*ofs[6]) = v[6];
+      if (likely(mask[7])) *(float*)(((char*)ptr)+scale*ofs[7]) = v[7];
 #endif
 #endif
     }
     }
 
 
-    static __forceinline void store(const vboolf8& mask, int8_t* ptr, const vint8& ofs, const vfloat8& v) {
-      scatter<1>(mask,ptr,ofs,v);
-    }
-    static __forceinline void store(const vboolf8& mask, float* ptr, const vint8& ofs, const vfloat8& v) {
-      scatter<4>(mask,ptr,ofs,v);
-    }
-
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -241,60 +215,27 @@ namespace embree
   __forceinline vfloat8 toFloat(const vint8&   a) { return vfloat8(a); }
   __forceinline vfloat8 toFloat(const vint8&   a) { return vfloat8(a); }
 
 
   __forceinline vfloat8 operator +(const vfloat8& a) { return a; }
   __forceinline vfloat8 operator +(const vfloat8& a) { return a; }
-#if !defined(__aarch64__)
   __forceinline vfloat8 operator -(const vfloat8& a) {
   __forceinline vfloat8 operator -(const vfloat8& a) {
     const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000)); 
     const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000)); 
     return _mm256_xor_ps(a, mask);
     return _mm256_xor_ps(a, mask);
   }
   }
-#else
-  __forceinline vfloat8 operator -(const vfloat8& a) {
-      __m256 res;
-      res.lo = vnegq_f32(a.v.lo);
-      res.hi = vnegq_f32(a.v.hi);
-      return res;
-}
-#endif
-
-#if !defined(__aarch64__)
-__forceinline vfloat8 abs(const vfloat8& a) {
-  const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff));
-  return _mm256_and_ps(a, mask);
-}
-#else
-__forceinline vfloat8 abs(const vfloat8& a) {
-    __m256 res;
-    res.lo = vabsq_f32(a.v.lo);
-    res.hi = vabsq_f32(a.v.hi);
-    return res;
-}
-#endif
-
-#if !defined(__aarch64__)
+  __forceinline vfloat8 abs(const vfloat8& a) {
+    const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff));
+    return _mm256_and_ps(a, mask);
+  }
   __forceinline vfloat8 sign   (const vfloat8& a) { return _mm256_blendv_ps(vfloat8(one), -vfloat8(one), _mm256_cmp_ps(a, vfloat8(zero), _CMP_NGE_UQ)); }
   __forceinline vfloat8 sign   (const vfloat8& a) { return _mm256_blendv_ps(vfloat8(one), -vfloat8(one), _mm256_cmp_ps(a, vfloat8(zero), _CMP_NGE_UQ)); }
-#else
-  __forceinline vfloat8 sign   (const vfloat8& a) { return _mm256_blendv_ps(vfloat8(one), -vfloat8(one), _mm256_cmplt_ps(a, vfloat8(zero))); }
-#endif
   __forceinline vfloat8 signmsk(const vfloat8& a) { return _mm256_and_ps(a,_mm256_castsi256_ps(_mm256_set1_epi32(0x80000000))); }
   __forceinline vfloat8 signmsk(const vfloat8& a) { return _mm256_and_ps(a,_mm256_castsi256_ps(_mm256_set1_epi32(0x80000000))); }
 
 
 
 
   static __forceinline vfloat8 rcp(const vfloat8& a)
   static __forceinline vfloat8 rcp(const vfloat8& a)
   {
   {
-#if defined(BUILD_IOS) && defined(__aarch64__)
-    // ios devices are faster doing full divide, no need for NR fixup
-    vfloat8 ret;
-    const float32x4_t one = vdupq_n_f32(1.0f);
-    ret.v.lo = vdivq_f32(one, a.v.lo);
-    ret.v.hi = vdivq_f32(one, a.v.hi);
-    return ret;
-#endif
-
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
     const vfloat8 r = _mm256_rcp14_ps(a);
     const vfloat8 r = _mm256_rcp14_ps(a);
 #else
 #else
     const vfloat8 r = _mm256_rcp_ps(a);
     const vfloat8 r = _mm256_rcp_ps(a);
 #endif
 #endif
-      
-#if defined(__AVX2__) //&& !defined(aarch64)
+
+#if defined(__AVX2__)
     return _mm256_mul_ps(r, _mm256_fnmadd_ps(r, a, vfloat8(2.0f)));
     return _mm256_mul_ps(r, _mm256_fnmadd_ps(r, a, vfloat8(2.0f)));
 #else
 #else
     return _mm256_mul_ps(r, _mm256_sub_ps(vfloat8(2.0f), _mm256_mul_ps(r, a)));
     return _mm256_mul_ps(r, _mm256_sub_ps(vfloat8(2.0f), _mm256_mul_ps(r, a)));
@@ -443,29 +384,17 @@ __forceinline vfloat8 abs(const vfloat8& a) {
   static __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
   static __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
     return _mm256_mask_blend_ps(m, f, t);
     return _mm256_mask_blend_ps(m, f, t);
   }
   }
-#elif !defined(__aarch64__)
-  __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_EQ_OQ);  }
-  __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NEQ_UQ); }
-  __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LT_OS);  }
-  __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLT_US); }
-  __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLE_US); }
-  __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LE_OS);  }
-
-  __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
-    return _mm256_blendv_ps(f, t, m); 
-  }
 #else
 #else
-  __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmpeq_ps(a, b);  }
-  __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmpneq_ps(a, b); }
-  __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmplt_ps(a, b);  }
-  __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmpge_ps(a, b);  }
-  __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmpgt_ps(a, b);  }
-  __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmple_ps(a, b);  }
+  static __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_EQ_OQ);  }
+  static __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NEQ_UQ); }
+  static __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LT_OS);  }
+  static __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLT_US); }
+  static __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLE_US); }
+  static __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LE_OS);  }
 
 
-  __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
-    return _mm256_blendv_ps(f, t, m);
+  static __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
+    return _mm256_blendv_ps(f, t, m); 
   }
   }
-
 #endif
 #endif
 
 
   template<int mask>
   template<int mask>
@@ -534,17 +463,10 @@ __forceinline vfloat8 abs(const vfloat8& a) {
   /// Rounding Functions
   /// Rounding Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if !defined(__aarch64__)
   __forceinline vfloat8 floor(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline vfloat8 floor(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEG_INF    ); }
   __forceinline vfloat8 ceil (const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_POS_INF    ); }
   __forceinline vfloat8 ceil (const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_POS_INF    ); }
   __forceinline vfloat8 trunc(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_ZERO       ); }
   __forceinline vfloat8 trunc(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_ZERO       ); }
   __forceinline vfloat8 round(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
   __forceinline vfloat8 round(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
-#else
-  __forceinline vfloat8 floor(const vfloat8& a) { return _mm256_floor_ps(a); }
-  __forceinline vfloat8 ceil (const vfloat8& a) { return _mm256_ceil_ps(a); }
-#endif
-
-
   __forceinline vfloat8 frac (const vfloat8& a) { return a-floor(a); }
   __forceinline vfloat8 frac (const vfloat8& a) { return a-floor(a); }
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -579,11 +501,9 @@ __forceinline vfloat8 abs(const vfloat8& a) {
     return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
     return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
   }
   }
 
 
-#if !defined(__aarch64__)
   template<> __forceinline vfloat8 shuffle<0, 0, 2, 2>(const vfloat8& v) { return _mm256_moveldup_ps(v); }
   template<> __forceinline vfloat8 shuffle<0, 0, 2, 2>(const vfloat8& v) { return _mm256_moveldup_ps(v); }
   template<> __forceinline vfloat8 shuffle<1, 1, 3, 3>(const vfloat8& v) { return _mm256_movehdup_ps(v); }
   template<> __forceinline vfloat8 shuffle<1, 1, 3, 3>(const vfloat8& v) { return _mm256_movehdup_ps(v); }
   template<> __forceinline vfloat8 shuffle<0, 1, 0, 1>(const vfloat8& v) { return _mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(v))); }
   template<> __forceinline vfloat8 shuffle<0, 1, 0, 1>(const vfloat8& v) { return _mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(v))); }
-#endif
 
 
   __forceinline vfloat8 broadcast(const float* ptr) { return _mm256_broadcast_ss(ptr); }
   __forceinline vfloat8 broadcast(const float* ptr) { return _mm256_broadcast_ss(ptr); }
   template<size_t i> __forceinline vfloat8 insert4(const vfloat8& a, const vfloat4& b) { return _mm256_insertf128_ps(a, b, i); }
   template<size_t i> __forceinline vfloat8 insert4(const vfloat8& a, const vfloat4& b) { return _mm256_insertf128_ps(a, b, i); }
@@ -592,10 +512,8 @@ __forceinline vfloat8 abs(const vfloat8& a) {
 
 
   __forceinline float toScalar(const vfloat8& v) { return _mm_cvtss_f32(_mm256_castps256_ps128(v)); }
   __forceinline float toScalar(const vfloat8& v) { return _mm_cvtss_f32(_mm256_castps256_ps128(v)); }
 
 
-  __forceinline vfloat8 assign(const vfloat4& a) { return _mm256_castps128_ps256(a); }
-
-#if defined (__AVX2__) && !defined(__aarch64__)
-  __forceinline vfloat8 permute(const vfloat8& a, const __m256i& index) {
+#if defined (__AVX2__)
+  static __forceinline vfloat8 permute(const vfloat8& a, const __m256i& index) {
     return _mm256_permutevar8x32_ps(a, index);
     return _mm256_permutevar8x32_ps(a, index);
   }
   }
 #endif
 #endif
@@ -618,14 +536,6 @@ __forceinline vfloat8 abs(const vfloat8& a) {
   }
   }
 #endif
 #endif
 
 
-  __forceinline vfloat4 broadcast4f(const vfloat8& a, const size_t k) {
-    return vfloat4::broadcast(&a[k]);
-  }
-
-  __forceinline vfloat8 broadcast8f(const vfloat8& a, const size_t k) {
-    return vfloat8::broadcast(&a[k]);
-  }
-
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
   static __forceinline vfloat8 shift_right_1(const vfloat8& x) {
   static __forceinline vfloat8 shift_right_1(const vfloat8& x) {
     return align_shift_right<1>(zero,x);
     return align_shift_right<1>(zero,x);
@@ -699,7 +609,7 @@ __forceinline vfloat8 abs(const vfloat8& a) {
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
-#if !defined(__aarch64__)
+
   __forceinline vfloat8 vreduce_min2(const vfloat8& v) { return min(v,shuffle<1,0,3,2>(v)); }
   __forceinline vfloat8 vreduce_min2(const vfloat8& v) { return min(v,shuffle<1,0,3,2>(v)); }
   __forceinline vfloat8 vreduce_min4(const vfloat8& v) { vfloat8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
   __forceinline vfloat8 vreduce_min4(const vfloat8& v) { vfloat8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
   __forceinline vfloat8 vreduce_min (const vfloat8& v) { vfloat8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
   __forceinline vfloat8 vreduce_min (const vfloat8& v) { vfloat8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
@@ -715,14 +625,7 @@ __forceinline vfloat8 abs(const vfloat8& a) {
   __forceinline float reduce_min(const vfloat8& v) { return toScalar(vreduce_min(v)); }
   __forceinline float reduce_min(const vfloat8& v) { return toScalar(vreduce_min(v)); }
   __forceinline float reduce_max(const vfloat8& v) { return toScalar(vreduce_max(v)); }
   __forceinline float reduce_max(const vfloat8& v) { return toScalar(vreduce_max(v)); }
   __forceinline float reduce_add(const vfloat8& v) { return toScalar(vreduce_add(v)); }
   __forceinline float reduce_add(const vfloat8& v) { return toScalar(vreduce_add(v)); }
-#else
-  __forceinline float reduce_min(const vfloat8& v) { return vminvq_f32(_mm_min_ps(v.v.lo,v.v.hi)); }
-  __forceinline float reduce_max(const vfloat8& v) { return vmaxvq_f32(_mm_max_ps(v.v.lo,v.v.hi)); }
-  __forceinline vfloat8 vreduce_min(const vfloat8& v) { return vfloat8(reduce_min(v)); }
-  __forceinline vfloat8 vreduce_max(const vfloat8& v) { return vfloat8(reduce_max(v)); }
-  __forceinline float reduce_add(const vfloat8& v) { return vaddvq_f32(_mm_add_ps(v.v.lo,v.v.hi)); }
 
 
-#endif
   __forceinline size_t select_min(const vboolf8& valid, const vfloat8& v) 
   __forceinline size_t select_min(const vboolf8& valid, const vfloat8& v) 
   { 
   { 
     const vfloat8 a = select(valid,v,vfloat8(pos_inf)); 
     const vfloat8 a = select(valid,v,vfloat8(pos_inf)); 
@@ -845,3 +748,11 @@ __forceinline vfloat8 abs(const vfloat8& a) {
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 19 - 37
thirdparty/embree-aarch64/common/simd/vint16_avx512.h → thirdparty/embree/common/simd/vint16_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 { 
 { 
   /* 16-wide AVX-512 integer type */
   /* 16-wide AVX-512 integer type */
@@ -90,10 +98,10 @@ namespace embree
 
 
     static __forceinline vint16 load (const void* addr) { return _mm512_load_si512((int*)addr); }
     static __forceinline vint16 load (const void* addr) { return _mm512_load_si512((int*)addr); }
 
 
-    static __forceinline vint16 load(const uint8_t* ptr) { return _mm512_cvtepu8_epi32(_mm_load_si128((__m128i*)ptr)); }
+    static __forceinline vint16 load(const unsigned char* ptr) { return _mm512_cvtepu8_epi32(_mm_load_si128((__m128i*)ptr)); }
     static __forceinline vint16 load(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_load_si256((__m256i*)ptr)); }
     static __forceinline vint16 load(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_load_si256((__m256i*)ptr)); }
 
 
-    static __forceinline vint16 loadu(const uint8_t* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+    static __forceinline vint16 loadu(const unsigned char* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
     static __forceinline vint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
     static __forceinline vint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
 
 
     static __forceinline vint16 loadu(const void* addr) { return _mm512_loadu_si512(addr); }
     static __forceinline vint16 loadu(const void* addr) { return _mm512_loadu_si512(addr); }
@@ -109,20 +117,6 @@ namespace embree
 
 
     static __forceinline void store_nt(void* __restrict__ ptr, const vint16& a) { _mm512_stream_si512((__m512i*)ptr,a); }
     static __forceinline void store_nt(void* __restrict__ ptr, const vint16& a) { _mm512_stream_si512((__m512i*)ptr,a); }
 
 
-    /* pass by value to avoid compiler generating inefficient code */
-    static __forceinline void storeu_compact(const vboolf16 mask, void* addr, vint16 reg) {
-      _mm512_mask_compressstoreu_epi32(addr,mask,reg);
-    }
-
-    static __forceinline void storeu_compact_single(const vboolf16 mask, void* addr, vint16 reg) {
-      //_mm512_mask_compressstoreu_epi32(addr,mask,reg);
-      *(float*)addr = mm512_cvtss_f32(_mm512_mask_compress_ps(_mm512_castsi512_ps(reg),mask,_mm512_castsi512_ps(reg)));
-    }
-
-    static __forceinline vint16 compact64bit(const vboolf16& mask, vint16 &v) {
-      return _mm512_mask_compress_epi64(v,mask,v);
-    }
-
     static __forceinline vint16 compact(const vboolf16& mask, vint16 &v) {
     static __forceinline vint16 compact(const vboolf16& mask, vint16 &v) {
       return _mm512_mask_compress_epi32(v,mask,v);
       return _mm512_mask_compress_epi32(v,mask,v);
     }
     }
@@ -160,10 +154,6 @@ namespace embree
       _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
       _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
     }
     }
 
 
-    static __forceinline vint16 broadcast64bit(size_t v) {
-      return _mm512_set1_epi64(v);
-    }
-
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -313,18 +303,6 @@ namespace embree
     return _mm512_mask_or_epi32(f,m,t,t); 
     return _mm512_mask_or_epi32(f,m,t,t); 
   }
   }
 
 
-  __forceinline void xchg(const vboolf16& m, vint16& a, vint16& b) {
-    const vint16 c = a; a = select(m,b,a); b = select(m,c,b);
-  }
-
-  __forceinline vboolf16 test(const vboolf16& m, const vint16& a, const vint16& b) {
-    return _mm512_mask_test_epi32_mask(m,a,b);
-  }
-
-  __forceinline vboolf16 test(const vint16& a, const vint16& b) {
-    return _mm512_test_epi32_mask(a,b);
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Movement/Shifting/Shuffling Functions
   // Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -363,10 +341,6 @@ namespace embree
 
 
   template<int i> __forceinline vint16 insert4(const vint16& a, const vint4& b) { return _mm512_inserti32x4(a, b, i); }
   template<int i> __forceinline vint16 insert4(const vint16& a, const vint4& b) { return _mm512_inserti32x4(a, b, i); }
 
 
-  __forceinline size_t extract64bit(const vint16& v) {
-    return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
-  }
-
   template<int N, int i>
   template<int N, int i>
   vint<N> extractN(const vint16& v);
   vint<N> extractN(const vint16& v);
 
 
@@ -488,3 +462,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 80 - 163
thirdparty/embree-aarch64/common/simd/vint4_sse2.h → thirdparty/embree/common/simd/vint4_sse2.h

@@ -1,10 +1,18 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
 #include "../math/math.h"
 #include "../math/math.h"
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide SSE integer type */
   /* 4-wide SSE integer type */
@@ -23,7 +31,7 @@ namespace embree
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Constructors, Assignment & Cast Operators
     /// Constructors, Assignment & Cast Operators
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
-
+    
     __forceinline vint() {}
     __forceinline vint() {}
     __forceinline vint(const vint4& a) { v = a.v; }
     __forceinline vint(const vint4& a) { v = a.v; }
     __forceinline vint4& operator =(const vint4& a) { v = a.v; return *this; }
     __forceinline vint4& operator =(const vint4& a) { v = a.v; return *this; }
@@ -68,7 +76,7 @@ namespace embree
 
 
     static __forceinline void store (void* ptr, const vint4& v) { _mm_store_si128((__m128i*)ptr,v); }
     static __forceinline void store (void* ptr, const vint4& v) { _mm_store_si128((__m128i*)ptr,v); }
     static __forceinline void storeu(void* ptr, const vint4& v) { _mm_storeu_si128((__m128i*)ptr,v); }
     static __forceinline void storeu(void* ptr, const vint4& v) { _mm_storeu_si128((__m128i*)ptr,v); }
-
+    
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
 
 
     static __forceinline vint4 compact(const vboolf4& mask, vint4 &v) {
     static __forceinline vint4 compact(const vboolf4& mask, vint4 &v) {
@@ -98,81 +106,61 @@ namespace embree
 #endif
 #endif
 
 
 
 
-#if defined(__aarch64__)
-    static __forceinline vint4 load(const uint8_t* ptr) {
-        return _mm_load4epu8_epi32(((__m128i*)ptr));
-    }
-    static __forceinline vint4 loadu(const uint8_t* ptr) {
-        return  _mm_load4epu8_epi32(((__m128i*)ptr));
-    }
-#elif defined(__SSE4_1__)
-    static __forceinline vint4 load(const uint8_t* ptr) {
+#if defined(__SSE4_1__)
+    static __forceinline vint4 load(const unsigned char* ptr) {
       return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
       return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
     }
     }
 
 
-    static __forceinline vint4 loadu(const uint8_t* ptr) {
+    static __forceinline vint4 loadu(const unsigned char* ptr) {
       return  _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
       return  _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
     }
     }
 #else
 #else
 
 
-    static __forceinline vint4 load(const uint8_t* ptr) {
+    static __forceinline vint4 load(const unsigned char* ptr) {
       return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
       return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
-    }
+    } 
 
 
-    static __forceinline vint4 loadu(const uint8_t* ptr) {
+    static __forceinline vint4 loadu(const unsigned char* ptr) {
       return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
       return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
     }
     }
 
 
 #endif
 #endif
 
 
     static __forceinline vint4 load(const unsigned short* ptr) {
     static __forceinline vint4 load(const unsigned short* ptr) {
-#if defined(__aarch64__)
-      return __m128i(vmovl_u16(vld1_u16(ptr)));
-#elif defined (__SSE4_1__)
+#if defined (__SSE4_1__)
       return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
       return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
 #else
 #else
       return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
       return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
 #endif
 #endif
-    }
+    } 
 
 
-    static __forceinline void store(uint8_t* ptr, const vint4& v) {
-#if defined(__aarch64__)
-        int32x4_t x = v;
-        uint16x4_t y = vqmovn_u32(uint32x4_t(x));
-        uint8x8_t z = vqmovn_u16(vcombine_u16(y, y));
-        vst1_lane_u32((uint32_t *)ptr,uint32x2_t(z), 0);
-#elif defined(__SSE4_1__)
+    static __forceinline void store(unsigned char* ptr, const vint4& v) {
+#if defined(__SSE4_1__)
       __m128i x = v;
       __m128i x = v;
       x = _mm_packus_epi32(x, x);
       x = _mm_packus_epi32(x, x);
       x = _mm_packus_epi16(x, x);
       x = _mm_packus_epi16(x, x);
       *(int*)ptr = _mm_cvtsi128_si32(x);
       *(int*)ptr = _mm_cvtsi128_si32(x);
 #else
 #else
       for (size_t i=0;i<4;i++)
       for (size_t i=0;i<4;i++)
-        ptr[i] = (uint8_t)v[i];
+        ptr[i] = (unsigned char)v[i];
 #endif
 #endif
     }
     }
 
 
     static __forceinline void store(unsigned short* ptr, const vint4& v) {
     static __forceinline void store(unsigned short* ptr, const vint4& v) {
-#if defined(__aarch64__)
-      uint32x4_t x = uint32x4_t(v.v);
-      uint16x4_t y = vqmovn_u32(x);
-      vst1_u16(ptr, y);
-#else
       for (size_t i=0;i<4;i++)
       for (size_t i=0;i<4;i++)
         ptr[i] = (unsigned short)v[i];
         ptr[i] = (unsigned short)v[i];
-#endif
     }
     }
 
 
     static __forceinline vint4 load_nt(void* ptr) {
     static __forceinline vint4 load_nt(void* ptr) {
-#if defined(__aarch64__) || defined(__SSE4_1__)
-      return _mm_stream_load_si128((__m128i*)ptr);
+#if defined(__SSE4_1__)
+      return _mm_stream_load_si128((__m128i*)ptr); 
 #else
 #else
-      return _mm_load_si128((__m128i*)ptr);
+      return _mm_load_si128((__m128i*)ptr); 
 #endif
 #endif
     }
     }
-
+    
     static __forceinline void store_nt(void* ptr, const vint4& v) {
     static __forceinline void store_nt(void* ptr, const vint4& v) {
-#if !defined(__aarch64__) && defined(__SSE4_1__)
+#if defined(__SSE4_1__)
       _mm_stream_ps((float*)ptr, _mm_castsi128_ps(v));
       _mm_stream_ps((float*)ptr, _mm_castsi128_ps(v));
 #else
 #else
       _mm_store_si128((__m128i*)ptr,v);
       _mm_store_si128((__m128i*)ptr,v);
@@ -181,14 +169,14 @@ namespace embree
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vint4 gather(const int* ptr, const vint4& index) {
     static __forceinline vint4 gather(const int* ptr, const vint4& index) {
-#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__AVX2__)
       return _mm_i32gather_epi32(ptr, index, scale);
       return _mm_i32gather_epi32(ptr, index, scale);
 #else
 #else
       return vint4(
       return vint4(
-          *(int*)(((int8_t*)ptr)+scale*index[0]),
-          *(int*)(((int8_t*)ptr)+scale*index[1]),
-          *(int*)(((int8_t*)ptr)+scale*index[2]),
-          *(int*)(((int8_t*)ptr)+scale*index[3]));
+          *(int*)(((char*)ptr)+scale*index[0]),
+          *(int*)(((char*)ptr)+scale*index[1]),
+          *(int*)(((char*)ptr)+scale*index[2]),
+          *(int*)(((char*)ptr)+scale*index[3]));
 #endif
 #endif
     }
     }
 
 
@@ -197,13 +185,13 @@ namespace embree
       vint4 r = zero;
       vint4 r = zero;
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
       return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
-#elif defined(__AVX2__) && !defined(__aarch64__)
+#elif defined(__AVX2__)
       return _mm_mask_i32gather_epi32(r, ptr, index, mask, scale);
       return _mm_mask_i32gather_epi32(r, ptr, index, mask, scale);
 #else
 #else
-      if (likely(mask[0])) r[0] = *(int*)(((int8_t*)ptr)+scale*index[0]);
-      if (likely(mask[1])) r[1] = *(int*)(((int8_t*)ptr)+scale*index[1]);
-      if (likely(mask[2])) r[2] = *(int*)(((int8_t*)ptr)+scale*index[2]);
-      if (likely(mask[3])) r[3] = *(int*)(((int8_t*)ptr)+scale*index[3]);
+      if (likely(mask[0])) r[0] = *(int*)(((char*)ptr)+scale*index[0]);
+      if (likely(mask[1])) r[1] = *(int*)(((char*)ptr)+scale*index[1]);
+      if (likely(mask[2])) r[2] = *(int*)(((char*)ptr)+scale*index[2]);
+      if (likely(mask[3])) r[3] = *(int*)(((char*)ptr)+scale*index[3]);
       return r;
       return r;
 #endif
 #endif
     }
     }
@@ -214,10 +202,10 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm_i32scatter_epi32((int*)ptr, index, v, scale);
       _mm_i32scatter_epi32((int*)ptr, index, v, scale);
 #else
 #else
-      *(int*)(((int8_t*)ptr)+scale*index[0]) = v[0];
-      *(int*)(((int8_t*)ptr)+scale*index[1]) = v[1];
-      *(int*)(((int8_t*)ptr)+scale*index[2]) = v[2];
-      *(int*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+      *(int*)(((char*)ptr)+scale*index[0]) = v[0];
+      *(int*)(((char*)ptr)+scale*index[1]) = v[1];
+      *(int*)(((char*)ptr)+scale*index[2]) = v[2];
+      *(int*)(((char*)ptr)+scale*index[3]) = v[3];
 #endif
 #endif
     }
     }
 
 
@@ -227,14 +215,14 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm_mask_i32scatter_epi32((int*)ptr, mask, index, v, scale);
       _mm_mask_i32scatter_epi32((int*)ptr, mask, index, v, scale);
 #else
 #else
-      if (likely(mask[0])) *(int*)(((int8_t*)ptr)+scale*index[0]) = v[0];
-      if (likely(mask[1])) *(int*)(((int8_t*)ptr)+scale*index[1]) = v[1];
-      if (likely(mask[2])) *(int*)(((int8_t*)ptr)+scale*index[2]) = v[2];
-      if (likely(mask[3])) *(int*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+      if (likely(mask[0])) *(int*)(((char*)ptr)+scale*index[0]) = v[0];
+      if (likely(mask[1])) *(int*)(((char*)ptr)+scale*index[1]) = v[1];
+      if (likely(mask[2])) *(int*)(((char*)ptr)+scale*index[2]) = v[2];
+      if (likely(mask[3])) *(int*)(((char*)ptr)+scale*index[3]) = v[3];
 #endif
 #endif
     }
     }
 
 
-#if defined(__x86_64__) || defined(__aarch64__)
+#if defined(__x86_64__)
     static __forceinline vint4 broadcast64(long long a) { return _mm_set1_epi64x(a); }
     static __forceinline vint4 broadcast64(long long a) { return _mm_set1_epi64x(a); }
 #endif
 #endif
 
 
@@ -248,12 +236,10 @@ namespace embree
     friend __forceinline vint4 select(const vboolf4& m, const vint4& t, const vint4& f) {
     friend __forceinline vint4 select(const vboolf4& m, const vint4& t, const vint4& f) {
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       return _mm_mask_blend_epi32(m, (__m128i)f, (__m128i)t);
       return _mm_mask_blend_epi32(m, (__m128i)f, (__m128i)t);
-#elif defined(__aarch64__)
-      return _mm_castps_si128(_mm_blendv_ps((__m128)f.v,(__m128) t.v, (__m128)m.v));
 #elif defined(__SSE4_1__)
 #elif defined(__SSE4_1__)
-      return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+      return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m)); 
 #else
 #else
-      return _mm_or_si128(_mm_and_si128(m, t), _mm_andnot_si128(m, f));
+      return _mm_or_si128(_mm_and_si128(m, t), _mm_andnot_si128(m, f)); 
 #endif
 #endif
     }
     }
   };
   };
@@ -270,9 +256,7 @@ namespace embree
 
 
   __forceinline vint4 operator +(const vint4& a) { return a; }
   __forceinline vint4 operator +(const vint4& a) { return a; }
   __forceinline vint4 operator -(const vint4& a) { return _mm_sub_epi32(_mm_setzero_si128(), a); }
   __forceinline vint4 operator -(const vint4& a) { return _mm_sub_epi32(_mm_setzero_si128(), a); }
-#if defined(__aarch64__)
-  __forceinline vint4 abs(const vint4& a) { return vabsq_s32(a.v); }
-#elif defined(__SSSE3__)
+#if defined(__SSSE3__)
   __forceinline vint4 abs(const vint4& a) { return _mm_abs_epi32(a); }
   __forceinline vint4 abs(const vint4& a) { return _mm_abs_epi32(a); }
 #endif
 #endif
 
 
@@ -288,7 +272,7 @@ namespace embree
   __forceinline vint4 operator -(const vint4& a, int          b) { return a - vint4(b); }
   __forceinline vint4 operator -(const vint4& a, int          b) { return a - vint4(b); }
   __forceinline vint4 operator -(int          a, const vint4& b) { return vint4(a) - b; }
   __forceinline vint4 operator -(int          a, const vint4& b) { return vint4(a) - b; }
 
 
-#if (defined(__aarch64__)) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline vint4 operator *(const vint4& a, const vint4& b) { return _mm_mullo_epi32(a, b); }
   __forceinline vint4 operator *(const vint4& a, const vint4& b) { return _mm_mullo_epi32(a, b); }
 #else
 #else
   __forceinline vint4 operator *(const vint4& a, const vint4& b) { return vint4(a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]); }
   __forceinline vint4 operator *(const vint4& a, const vint4& b) { return vint4(a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]); }
@@ -308,34 +292,34 @@ namespace embree
   __forceinline vint4 operator ^(const vint4& a, int          b) { return a ^ vint4(b); }
   __forceinline vint4 operator ^(const vint4& a, int          b) { return a ^ vint4(b); }
   __forceinline vint4 operator ^(int          a, const vint4& b) { return vint4(a) ^ b; }
   __forceinline vint4 operator ^(int          a, const vint4& b) { return vint4(a) ^ b; }
 
 
-  __forceinline vint4 operator <<(const vint4& a, const int n) { return _mm_slli_epi32(a, n); }
-  __forceinline vint4 operator >>(const vint4& a, const int n) { return _mm_srai_epi32(a, n); }
+  __forceinline vint4 operator <<(const vint4& a, int n) { return _mm_slli_epi32(a, n); }
+  __forceinline vint4 operator >>(const vint4& a, int n) { return _mm_srai_epi32(a, n); }
 
 
   __forceinline vint4 sll (const vint4& a, int b) { return _mm_slli_epi32(a, b); }
   __forceinline vint4 sll (const vint4& a, int b) { return _mm_slli_epi32(a, b); }
   __forceinline vint4 sra (const vint4& a, int b) { return _mm_srai_epi32(a, b); }
   __forceinline vint4 sra (const vint4& a, int b) { return _mm_srai_epi32(a, b); }
   __forceinline vint4 srl (const vint4& a, int b) { return _mm_srli_epi32(a, b); }
   __forceinline vint4 srl (const vint4& a, int b) { return _mm_srli_epi32(a, b); }
-
+  
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Assignment Operators
   /// Assignment Operators
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
   __forceinline vint4& operator +=(vint4& a, const vint4& b) { return a = a + b; }
   __forceinline vint4& operator +=(vint4& a, const vint4& b) { return a = a + b; }
   __forceinline vint4& operator +=(vint4& a, int          b) { return a = a + b; }
   __forceinline vint4& operator +=(vint4& a, int          b) { return a = a + b; }
-
+  
   __forceinline vint4& operator -=(vint4& a, const vint4& b) { return a = a - b; }
   __forceinline vint4& operator -=(vint4& a, const vint4& b) { return a = a - b; }
   __forceinline vint4& operator -=(vint4& a, int          b) { return a = a - b; }
   __forceinline vint4& operator -=(vint4& a, int          b) { return a = a - b; }
 
 
-#if (defined(__aarch64__)) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline vint4& operator *=(vint4& a, const vint4& b) { return a = a * b; }
   __forceinline vint4& operator *=(vint4& a, const vint4& b) { return a = a * b; }
   __forceinline vint4& operator *=(vint4& a, int          b) { return a = a * b; }
   __forceinline vint4& operator *=(vint4& a, int          b) { return a = a * b; }
 #endif
 #endif
-
+  
   __forceinline vint4& operator &=(vint4& a, const vint4& b) { return a = a & b; }
   __forceinline vint4& operator &=(vint4& a, const vint4& b) { return a = a & b; }
   __forceinline vint4& operator &=(vint4& a, int          b) { return a = a & b; }
   __forceinline vint4& operator &=(vint4& a, int          b) { return a = a & b; }
-
+  
   __forceinline vint4& operator |=(vint4& a, const vint4& b) { return a = a | b; }
   __forceinline vint4& operator |=(vint4& a, const vint4& b) { return a = a | b; }
   __forceinline vint4& operator |=(vint4& a, int          b) { return a = a | b; }
   __forceinline vint4& operator |=(vint4& a, int          b) { return a = a | b; }
-
+  
   __forceinline vint4& operator <<=(vint4& a, int b) { return a = a << b; }
   __forceinline vint4& operator <<=(vint4& a, int b) { return a = a << b; }
   __forceinline vint4& operator >>=(vint4& a, int b) { return a = a >> b; }
   __forceinline vint4& operator >>=(vint4& a, int b) { return a = a >> b; }
 
 
@@ -402,15 +386,14 @@ namespace embree
 
 
   template<int mask>
   template<int mask>
   __forceinline vint4 select(const vint4& t, const vint4& f) {
   __forceinline vint4 select(const vint4& t, const vint4& f) {
-#if defined(__SSE4_1__)
+#if defined(__SSE4_1__) 
     return _mm_castps_si128(_mm_blend_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), mask));
     return _mm_castps_si128(_mm_blend_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), mask));
 #else
 #else
     return select(vboolf4(mask), t, f);
     return select(vboolf4(mask), t, f);
-#endif
+#endif    
   }
   }
 
 
-      
-#if defined(__aarch64__) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   __forceinline vint4 min(const vint4& a, const vint4& b) { return _mm_min_epi32(a, b); }
   __forceinline vint4 min(const vint4& a, const vint4& b) { return _mm_min_epi32(a, b); }
   __forceinline vint4 max(const vint4& a, const vint4& b) { return _mm_max_epi32(a, b); }
   __forceinline vint4 max(const vint4& a, const vint4& b) { return _mm_max_epi32(a, b); }
 
 
@@ -434,25 +417,16 @@ namespace embree
   __forceinline vint4 unpacklo(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
   __forceinline vint4 unpacklo(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
   __forceinline vint4 unpackhi(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
   __forceinline vint4 unpackhi(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
 
 
-#if defined(__aarch64__)
-    template<int i0, int i1, int i2, int i3>
-    __forceinline vint4 shuffle(const vint4& v) {
-        return vreinterpretq_s32_u8(vqtbl1q_u8( (uint8x16_t)v.v, _MN_SHUFFLE(i0, i1, i2, i3)));
-    }
-    template<int i0, int i1, int i2, int i3>
-    __forceinline vint4 shuffle(const vint4& a, const vint4& b) {
-        return vreinterpretq_s32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
-    }
-#else
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
   __forceinline vint4 shuffle(const vint4& v) {
   __forceinline vint4 shuffle(const vint4& v) {
     return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
     return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
   }
   }
+
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
   __forceinline vint4 shuffle(const vint4& a, const vint4& b) {
   __forceinline vint4 shuffle(const vint4& a, const vint4& b) {
     return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
     return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
   }
   }
-#endif
+
 #if defined(__SSE3__)
 #if defined(__SSE3__)
   template<> __forceinline vint4 shuffle<0, 0, 2, 2>(const vint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
   template<> __forceinline vint4 shuffle<0, 0, 2, 2>(const vint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
   template<> __forceinline vint4 shuffle<1, 1, 3, 3>(const vint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
   template<> __forceinline vint4 shuffle<1, 1, 3, 3>(const vint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
@@ -464,10 +438,7 @@ namespace embree
     return shuffle<i,i,i,i>(v);
     return shuffle<i,i,i,i>(v);
   }
   }
 
 
-#if defined(__aarch64__)
-    template<int src> __forceinline int extract(const vint4& b);
-    template<int dst> __forceinline vint4 insert(const vint4& a, const int b);
-#elif defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   template<int src> __forceinline int extract(const vint4& b) { return _mm_extract_epi32(b, src); }
   template<int src> __forceinline int extract(const vint4& b) { return _mm_extract_epi32(b, src); }
   template<int dst> __forceinline vint4 insert(const vint4& a, const int b) { return _mm_insert_epi32(a, b, dst); }
   template<int dst> __forceinline vint4 insert(const vint4& a, const int b) { return _mm_insert_epi32(a, b, dst); }
 #else
 #else
@@ -475,69 +446,19 @@ namespace embree
   template<int dst> __forceinline vint4 insert(const vint4& a, int b) { vint4 c = a; c[dst&3] = b; return c; }
   template<int dst> __forceinline vint4 insert(const vint4& a, int b) { vint4 c = a; c[dst&3] = b; return c; }
 #endif
 #endif
 
 
-#if defined(__aarch64__)
-    template<> __forceinline int extract<0>(const vint4& b) {
-        return b.v[0];
-    }
-    template<> __forceinline int extract<1>(const vint4& b) {
-        return b.v[1];
-    }
-    template<> __forceinline int extract<2>(const vint4& b) {
-        return b.v[2];
-    }
-    template<> __forceinline int extract<3>(const vint4& b) {
-        return b.v[3];
-    }
-    template<> __forceinline vint4 insert<0>(const vint4& a, int b)
-    {
-        vint4 c = a;
-        c[0] = b;
-        return c;
-    }
-    template<> __forceinline vint4 insert<1>(const vint4& a, int b)
-    {
-        vint4 c = a;
-        c[1] = b;
-        return c;
-    }
-    template<> __forceinline vint4 insert<2>(const vint4& a, int b)
-    {
-        vint4 c = a;
-        c[2] = b;
-        return c;
-    }
-    template<> __forceinline vint4 insert<3>(const vint4& a, int b)
-    {
-        vint4 c = a;
-        c[3] = b;
-        return c;
-    }
-      
-    __forceinline int toScalar(const vint4& v) {
-        return v[0];
-    }
-      
-    __forceinline size_t toSizeT(const vint4& v) {
-        uint64x2_t x = uint64x2_t(v.v);
-        return x[0];
-    }
-#else
+
   template<> __forceinline int extract<0>(const vint4& b) { return _mm_cvtsi128_si32(b); }
   template<> __forceinline int extract<0>(const vint4& b) { return _mm_cvtsi128_si32(b); }
 
 
   __forceinline int toScalar(const vint4& v) { return _mm_cvtsi128_si32(v); }
   __forceinline int toScalar(const vint4& v) { return _mm_cvtsi128_si32(v); }
 
 
-  __forceinline size_t toSizeT(const vint4& v) {
+  __forceinline size_t toSizeT(const vint4& v) { 
 #if defined(__WIN32__) && !defined(__X86_64__) // win32 workaround
 #if defined(__WIN32__) && !defined(__X86_64__) // win32 workaround
     return toScalar(v);
     return toScalar(v);
-#elif defined(__ARM_NEON)
-    // FIXME(LTE): Do we need a swap(i.e. use lane 1)?
-    return vgetq_lane_u64(*(reinterpret_cast<const uint64x2_t *>(&v)), 0);
 #else
 #else
-    return _mm_cvtsi128_si64(v);
+    return _mm_cvtsi128_si64(v); 
 #endif
 #endif
   }
   }
-#endif
-      
+
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
 
 
   __forceinline vint4 permute(const vint4 &a, const vint4 &index) {
   __forceinline vint4 permute(const vint4 &a, const vint4 &index) {
@@ -546,25 +467,15 @@ namespace embree
 
 
   template<int i>
   template<int i>
   __forceinline vint4 align_shift_right(const vint4& a, const vint4& b) {
   __forceinline vint4 align_shift_right(const vint4& a, const vint4& b) {
-    return _mm_alignr_epi32(a, b, i);
-  }
+    return _mm_alignr_epi32(a, b, i);    
+  }  
 #endif
 #endif
 
 
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if defined(__aarch64__) || defined(__SSE4_1__)
-      
-#if defined(__aarch64__)
-    __forceinline vint4 vreduce_min(const vint4& v) { int h = vminvq_s32(v); return vdupq_n_s32(h); }
-    __forceinline vint4 vreduce_max(const vint4& v) { int h = vmaxvq_s32(v); return vdupq_n_s32(h); }
-    __forceinline vint4 vreduce_add(const vint4& v) { int h = vaddvq_s32(v); return vdupq_n_s32(h); }
-      
-    __forceinline int reduce_min(const vint4& v) { return vminvq_s32(v); }
-    __forceinline int reduce_max(const vint4& v) { return vmaxvq_s32(v); }
-    __forceinline int reduce_add(const vint4& v) { return vaddvq_s32(v); }
-#else
+#if defined(__SSE4_1__)
   __forceinline vint4 vreduce_min(const vint4& v) { vint4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
   __forceinline vint4 vreduce_min(const vint4& v) { vint4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
   __forceinline vint4 vreduce_max(const vint4& v) { vint4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
   __forceinline vint4 vreduce_max(const vint4& v) { vint4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
   __forceinline vint4 vreduce_add(const vint4& v) { vint4 h = shuffle<1,0,3,2>(v)   + v ; return shuffle<2,3,0,1>(h)   + h ; }
   __forceinline vint4 vreduce_add(const vint4& v) { vint4 h = shuffle<1,0,3,2>(v)   + v ; return shuffle<2,3,0,1>(h)   + h ; }
@@ -572,8 +483,7 @@ namespace embree
   __forceinline int reduce_min(const vint4& v) { return toScalar(vreduce_min(v)); }
   __forceinline int reduce_min(const vint4& v) { return toScalar(vreduce_min(v)); }
   __forceinline int reduce_max(const vint4& v) { return toScalar(vreduce_max(v)); }
   __forceinline int reduce_max(const vint4& v) { return toScalar(vreduce_max(v)); }
   __forceinline int reduce_add(const vint4& v) { return toScalar(vreduce_add(v)); }
   __forceinline int reduce_add(const vint4& v) { return toScalar(vreduce_add(v)); }
-#endif
-      
+
   __forceinline size_t select_min(const vint4& v) { return bsf(movemask(v == vreduce_min(v))); }
   __forceinline size_t select_min(const vint4& v) { return bsf(movemask(v == vreduce_min(v))); }
   __forceinline size_t select_max(const vint4& v) { return bsf(movemask(v == vreduce_max(v))); }
   __forceinline size_t select_max(const vint4& v) { return bsf(movemask(v == vreduce_max(v))); }
 
 
@@ -592,7 +502,7 @@ namespace embree
   /// Sorting networks
   /// Sorting networks
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
 
 
-#if (defined(__aarch64__)) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
 
 
   __forceinline vint4 usort_ascending(const vint4& v)
   __forceinline vint4 usort_ascending(const vint4& v)
   {
   {
@@ -679,3 +589,10 @@ namespace embree
   }
   }
 }
 }
 
 
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 52 - 46
thirdparty/embree-aarch64/common/simd/vint8_avx.h → thirdparty/embree/common/simd/vint8_avx.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX integer type */
   /* 8-wide AVX integer type */
@@ -71,25 +79,20 @@ namespace embree
     static __forceinline void store (void* ptr, const vint8& f) { _mm256_store_ps((float*)ptr,_mm256_castsi256_ps(f)); }
     static __forceinline void store (void* ptr, const vint8& f) { _mm256_store_ps((float*)ptr,_mm256_castsi256_ps(f)); }
     static __forceinline void storeu(void* ptr, const vint8& f) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(f)); }
     static __forceinline void storeu(void* ptr, const vint8& f) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(f)); }
     
     
-#if !defined(__aarch64__)
     static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
     static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
     static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
     static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
-#else
-    static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,_mm256_castsi256_ps(f)); }
-    static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,_mm256_castsi256_ps(f)); }
-#endif
 
 
     static __forceinline void store_nt(void* ptr, const vint8& v) {
     static __forceinline void store_nt(void* ptr, const vint8& v) {
       _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
       _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
     }
     }
 
 
-    static __forceinline vint8 load(const uint8_t* ptr) {
+    static __forceinline vint8 load(const unsigned char* ptr) {
       vint4 il = vint4::load(ptr+0);
       vint4 il = vint4::load(ptr+0);
       vint4 ih = vint4::load(ptr+4);
       vint4 ih = vint4::load(ptr+4);
       return vint8(il,ih);
       return vint8(il,ih);
     }
     }
 
 
-    static __forceinline vint8 loadu(const uint8_t* ptr) {
+    static __forceinline vint8 loadu(const unsigned char* ptr) {
       vint4 il = vint4::loadu(ptr+0);
       vint4 il = vint4::loadu(ptr+0);
       vint4 ih = vint4::loadu(ptr+4);
       vint4 ih = vint4::loadu(ptr+4);
       return vint8(il,ih);
       return vint8(il,ih);
@@ -107,7 +110,7 @@ namespace embree
       return vint8(il,ih);
       return vint8(il,ih);
     }
     }
 
 
-    static __forceinline void store(uint8_t* ptr, const vint8& i) {
+    static __forceinline void store(unsigned char* ptr, const vint8& i) {
       vint4 il(i.vl);
       vint4 il(i.vl);
       vint4 ih(i.vh);
       vint4 ih(i.vh);
       vint4::store(ptr + 0,il);
       vint4::store(ptr + 0,il);
@@ -122,54 +125,54 @@ namespace embree
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vint8 gather(const int* ptr, const vint8& index) {
     static __forceinline vint8 gather(const int* ptr, const vint8& index) {
       return vint8(
       return vint8(
-          *(int*)(((int8_t*)ptr)+scale*index[0]),
-          *(int*)(((int8_t*)ptr)+scale*index[1]),
-          *(int*)(((int8_t*)ptr)+scale*index[2]),
-          *(int*)(((int8_t*)ptr)+scale*index[3]),
-          *(int*)(((int8_t*)ptr)+scale*index[4]),
-          *(int*)(((int8_t*)ptr)+scale*index[5]),
-          *(int*)(((int8_t*)ptr)+scale*index[6]),
-          *(int*)(((int8_t*)ptr)+scale*index[7]));
+          *(int*)(((char*)ptr)+scale*index[0]),
+          *(int*)(((char*)ptr)+scale*index[1]),
+          *(int*)(((char*)ptr)+scale*index[2]),
+          *(int*)(((char*)ptr)+scale*index[3]),
+          *(int*)(((char*)ptr)+scale*index[4]),
+          *(int*)(((char*)ptr)+scale*index[5]),
+          *(int*)(((char*)ptr)+scale*index[6]),
+          *(int*)(((char*)ptr)+scale*index[7]));
     }
     }
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vint8 gather(const vboolf8& mask, const int* ptr, const vint8& index) {
     static __forceinline vint8 gather(const vboolf8& mask, const int* ptr, const vint8& index) {
       vint8 r = zero;
       vint8 r = zero;
-      if (likely(mask[0])) r[0] = *(int*)(((int8_t*)ptr)+scale*index[0]);
-      if (likely(mask[1])) r[1] = *(int*)(((int8_t*)ptr)+scale*index[1]);
-      if (likely(mask[2])) r[2] = *(int*)(((int8_t*)ptr)+scale*index[2]);
-      if (likely(mask[3])) r[3] = *(int*)(((int8_t*)ptr)+scale*index[3]);
-      if (likely(mask[4])) r[4] = *(int*)(((int8_t*)ptr)+scale*index[4]);
-      if (likely(mask[5])) r[5] = *(int*)(((int8_t*)ptr)+scale*index[5]);
-      if (likely(mask[6])) r[6] = *(int*)(((int8_t*)ptr)+scale*index[6]);
-      if (likely(mask[7])) r[7] = *(int*)(((int8_t*)ptr)+scale*index[7]);
+      if (likely(mask[0])) r[0] = *(int*)(((char*)ptr)+scale*index[0]);
+      if (likely(mask[1])) r[1] = *(int*)(((char*)ptr)+scale*index[1]);
+      if (likely(mask[2])) r[2] = *(int*)(((char*)ptr)+scale*index[2]);
+      if (likely(mask[3])) r[3] = *(int*)(((char*)ptr)+scale*index[3]);
+      if (likely(mask[4])) r[4] = *(int*)(((char*)ptr)+scale*index[4]);
+      if (likely(mask[5])) r[5] = *(int*)(((char*)ptr)+scale*index[5]);
+      if (likely(mask[6])) r[6] = *(int*)(((char*)ptr)+scale*index[6]);
+      if (likely(mask[7])) r[7] = *(int*)(((char*)ptr)+scale*index[7]);
       return r;
       return r;
     }
     }
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline void scatter(void* ptr, const vint8& ofs, const vint8& v)
     static __forceinline void scatter(void* ptr, const vint8& ofs, const vint8& v)
     {
     {
-      *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
-      *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
-      *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
-      *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
-      *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
-      *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
-      *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
-      *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+      *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+      *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+      *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+      *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+      *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+      *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+      *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+      *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
     }
     }
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vint8& v)
     static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vint8& v)
     {
     {
-      if (likely(mask[0])) *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
-      if (likely(mask[1])) *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
-      if (likely(mask[2])) *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
-      if (likely(mask[3])) *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
-      if (likely(mask[4])) *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
-      if (likely(mask[5])) *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
-      if (likely(mask[6])) *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
-      if (likely(mask[7])) *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+      if (likely(mask[0])) *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+      if (likely(mask[1])) *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+      if (likely(mask[2])) *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+      if (likely(mask[3])) *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+      if (likely(mask[4])) *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+      if (likely(mask[5])) *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+      if (likely(mask[6])) *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+      if (likely(mask[7])) *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
     }
     }
 
 
 
 
@@ -315,11 +318,6 @@ namespace embree
     return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m)); 
     return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m)); 
   }
   }
 
 
-  __forceinline vint8 notand(const vboolf8& m, const vint8& f) {
-    return _mm256_castps_si256(_mm256_andnot_ps(m, _mm256_castsi256_ps(f))); 
-  }
-
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Movement/Shifting/Shuffling Functions
   /// Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -462,3 +460,11 @@ namespace embree
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 37 - 31
thirdparty/embree-aarch64/common/simd/vint8_avx2.h → thirdparty/embree/common/simd/vint8_avx2.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 8-wide AVX integer type */
   /* 8-wide AVX integer type */
@@ -67,8 +75,8 @@ namespace embree
     /// Loads and Stores
     /// Loads and Stores
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
 
 
-    static __forceinline vint8 load(const uint8_t* ptr)  { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
-    static __forceinline vint8 loadu(const uint8_t* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+    static __forceinline vint8 load(const unsigned char* ptr)  { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+    static __forceinline vint8 loadu(const unsigned char* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
     static __forceinline vint8 load(const unsigned short* ptr)  { return _mm256_cvtepu16_epi32(_mm_load_si128((__m128i*)ptr)); }
     static __forceinline vint8 load(const unsigned short* ptr)  { return _mm256_cvtepu16_epi32(_mm_load_si128((__m128i*)ptr)); }
     static __forceinline vint8 loadu(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr)); }
     static __forceinline vint8 loadu(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr)); }
 
 
@@ -108,7 +116,7 @@ namespace embree
       _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
       _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
     }
     }
 
 
-    static __forceinline void store(uint8_t* ptr, const vint8& i)
+    static __forceinline void store(unsigned char* ptr, const vint8& i)
     {
     {
       for (size_t j=0; j<8; j++)
       for (size_t j=0; j<8; j++)
         ptr[j] = i[j];
         ptr[j] = i[j];
@@ -140,14 +148,14 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm256_i32scatter_epi32((int*)ptr, ofs, v, scale);
       _mm256_i32scatter_epi32((int*)ptr, ofs, v, scale);
 #else
 #else
-      *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
-      *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
-      *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
-      *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
-      *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
-      *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
-      *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
-      *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+      *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+      *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+      *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+      *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+      *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+      *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+      *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+      *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
 #endif
 #endif
     }
     }
 
 
@@ -157,14 +165,14 @@ namespace embree
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       _mm256_mask_i32scatter_epi32((int*)ptr, mask, ofs, v, scale);
       _mm256_mask_i32scatter_epi32((int*)ptr, mask, ofs, v, scale);
 #else
 #else
-      if (likely(mask[0])) *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
-      if (likely(mask[1])) *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
-      if (likely(mask[2])) *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
-      if (likely(mask[3])) *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
-      if (likely(mask[4])) *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
-      if (likely(mask[5])) *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
-      if (likely(mask[6])) *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
-      if (likely(mask[7])) *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+      if (likely(mask[0])) *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+      if (likely(mask[1])) *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+      if (likely(mask[2])) *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+      if (likely(mask[3])) *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+      if (likely(mask[4])) *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+      if (likely(mask[5])) *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+      if (likely(mask[6])) *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+      if (likely(mask[7])) *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
 #endif
 #endif
     }
     }
 
 
@@ -385,9 +393,7 @@ namespace embree
 
 
   __forceinline int toScalar(const vint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
   __forceinline int toScalar(const vint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
 
 
-#if !defined(__aarch64__)
-
-__forceinline vint8 permute(const vint8& v, const __m256i& index) {
+  __forceinline vint8 permute(const vint8& v, const __m256i& index) {
     return _mm256_permutevar8x32_epi32(v, index);
     return _mm256_permutevar8x32_epi32(v, index);
   }
   }
 
 
@@ -395,8 +401,6 @@ __forceinline vint8 permute(const vint8& v, const __m256i& index) {
     return _mm256_castps_si256(_mm256_permutevar_ps(_mm256_castsi256_ps(v), index));
     return _mm256_castps_si256(_mm256_permutevar_ps(_mm256_castsi256_ps(v), index));
   }
   }
 
 
-
-
   template<int i>
   template<int i>
   static __forceinline vint8 align_shift_right(const vint8& a, const vint8& b) {
   static __forceinline vint8 align_shift_right(const vint8& a, const vint8& b) {
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
@@ -406,9 +410,6 @@ __forceinline vint8 permute(const vint8& v, const __m256i& index) {
 #endif
 #endif
   }  
   }  
 
 
-#endif
-
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -435,9 +436,6 @@ __forceinline vint8 permute(const vint8& v, const __m256i& index) {
   __forceinline size_t select_min(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
   __forceinline size_t select_min(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
   __forceinline size_t select_max(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
   __forceinline size_t select_max(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
 
 
-
-  __forceinline vint8 assign(const vint4& a) { return _mm256_castsi128_si256(a); }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Sorting networks
   /// Sorting networks
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -510,3 +508,11 @@ __forceinline vint8 permute(const vint8& v, const __m256i& index) {
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
     return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 17 - 23
thirdparty/embree-aarch64/common/simd/vllong4_avx2.h → thirdparty/embree/common/simd/vllong4_avx2.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 { 
 { 
   /* 4-wide AVX2 64-bit long long type */
   /* 4-wide AVX2 64-bit long long type */
@@ -95,16 +103,6 @@ namespace embree
 #endif
 #endif
     }
     }
 
 
-    static __forceinline vllong4 broadcast64bit(size_t v) {
-      return _mm256_set1_epi64x(v);
-    }
-
-    static __forceinline size_t extract64bit(const vllong4& v)
-    {
-      return _mm_cvtsi128_si64(_mm256_castsi256_si128(v));
-    }
-
-
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -276,18 +274,6 @@ namespace embree
   __forceinline vboold4 le(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a <= b); }
   __forceinline vboold4 le(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a <= b); }
 #endif
 #endif
 
 
-  __forceinline void xchg(const vboold4& m, vllong4& a, vllong4& b) {
-    const vllong4 c = a; a = select(m,b,a); b = select(m,c,b);
-  }
-
-  __forceinline vboold4 test(const vllong4& a, const vllong4& b) {
-#if defined(__AVX512VL__)
-    return _mm256_test_epi64_mask(a,b);
-#else
-    return _mm256_testz_si256(a,b);
-#endif
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Movement/Shifting/Shuffling Functions
   // Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -356,3 +342,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 18 - 41
thirdparty/embree-aarch64/common/simd/vllong8_avx512.h → thirdparty/embree/common/simd/vllong8_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 { 
 { 
   /* 8-wide AVX-512 64-bit long long type */
   /* 8-wide AVX-512 64-bit long long type */
@@ -78,7 +86,7 @@ namespace embree
       return _mm512_load_si512(addr);
       return _mm512_load_si512(addr);
     }
     }
 
 
-    static __forceinline vllong8 load(const uint8_t* ptr) {
+    static __forceinline vllong8 load(const unsigned char* ptr) {
       return _mm512_cvtepu8_epi64(*(__m128i*)ptr); 
       return _mm512_cvtepu8_epi64(*(__m128i*)ptr); 
     }
     }
 
 
@@ -98,19 +106,6 @@ namespace embree
       _mm512_mask_store_epi64(addr,mask,v2);
       _mm512_mask_store_epi64(addr,mask,v2);
     }
     }
 
 
-    /* pass by value to avoid compiler generating inefficient code */
-    static __forceinline void storeu_compact(const vboold8 mask, void* addr, const vllong8& reg) {
-      _mm512_mask_compressstoreu_epi64(addr,mask,reg);
-    }
-
-    static __forceinline vllong8 compact64bit(const vboold8& mask, vllong8& v) {
-      return _mm512_mask_compress_epi64(v,mask,v);
-    }
-
-    static __forceinline vllong8 compact64bit(const vboold8& mask, vllong8& dest, const vllong8& source) {
-      return _mm512_mask_compress_epi64(dest,mask,source);
-    }
-
     static __forceinline vllong8 compact(const vboold8& mask, vllong8& v) {
     static __forceinline vllong8 compact(const vboold8& mask, vllong8& v) {
       return _mm512_mask_compress_epi64(v,mask,v);
       return _mm512_mask_compress_epi64(v,mask,v);
     }
     }
@@ -123,16 +118,6 @@ namespace embree
       return _mm512_mask_expand_epi64(b,mask,a);
       return _mm512_mask_expand_epi64(b,mask,a);
     }
     }
 
 
-    static __forceinline vllong8 broadcast64bit(size_t v) {
-      return _mm512_set1_epi64(v);
-    }
-
-    static __forceinline size_t extract64bit(const vllong8& v)
-    {
-      return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
-    }
-
-
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -271,18 +256,6 @@ namespace embree
     return _mm512_mask_or_epi64(f,m,t,t); 
     return _mm512_mask_or_epi64(f,m,t,t); 
   }
   }
 
 
-  __forceinline void xchg(const vboold8& m, vllong8& a, vllong8& b) {
-    const vllong8 c = a; a = select(m,b,a); b = select(m,c,b);
-  }
-
-  __forceinline vboold8 test(const vboold8& m, const vllong8& a, const vllong8& b) {
-    return _mm512_mask_test_epi64_mask(m,a,b);
-  }
-
-  __forceinline vboold8 test(const vllong8& a, const vllong8& b) {
-    return _mm512_test_epi64_mask(a,b);
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Movement/Shifting/Shuffling Functions
   // Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -321,10 +294,6 @@ namespace embree
     return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
     return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
   }
   }
 
 
-  __forceinline vllong8 zeroExtend32Bit(const __m512i& a) {
-    return _mm512_cvtepu32_epi64(_mm512_castsi512_si256(a));
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -379,3 +348,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 18 - 37
thirdparty/embree-aarch64/common/simd/vuint16_avx512.h → thirdparty/embree/common/simd/vuint16_avx512.h

@@ -1,8 +1,16 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 { 
 { 
   /* 16-wide AVX-512 unsigned integer type */
   /* 16-wide AVX-512 unsigned integer type */
@@ -83,7 +91,7 @@ namespace embree
       return _mm512_loadu_si512(addr);
       return _mm512_loadu_si512(addr);
     }
     }
 
 
-    static __forceinline vuint16 loadu(const uint8_t* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+    static __forceinline vuint16 loadu(const unsigned char* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
     static __forceinline vuint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
     static __forceinline vuint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
 
 
     static __forceinline vuint16 load(const vuint16* addr) {
     static __forceinline vuint16 load(const vuint16* addr) {
@@ -113,20 +121,6 @@ namespace embree
       _mm512_mask_store_epi32(addr,mask,v2);
       _mm512_mask_store_epi32(addr,mask,v2);
     }
     }
 
 
-    /* pass by value to avoid compiler generating inefficient code */
-    static __forceinline void storeu_compact(const vboolf16 mask, void* addr, const vuint16 reg) {
-      _mm512_mask_compressstoreu_epi32(addr,mask,reg);
-    }
-
-    static __forceinline void storeu_compact_single(const vboolf16 mask, void* addr, vuint16 reg) {
-      //_mm512_mask_compressstoreu_epi32(addr,mask,reg);
-      *(float*)addr = mm512_cvtss_f32(_mm512_mask_compress_ps(_mm512_castsi512_ps(reg),mask,_mm512_castsi512_ps(reg)));
-    }
-
-    static __forceinline vuint16 compact64bit(const vboolf16& mask, vuint16& v) {
-      return _mm512_mask_compress_epi64(v,mask,v);
-    }
-
     static __forceinline vuint16 compact(const vboolf16& mask, vuint16& v) {
     static __forceinline vuint16 compact(const vboolf16& mask, vuint16& v) {
       return _mm512_mask_compress_epi32(v,mask,v);
       return _mm512_mask_compress_epi32(v,mask,v);
     }
     }
@@ -164,15 +158,6 @@ namespace embree
       _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
       _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
     }
     }
 
 
-    static __forceinline vuint16 broadcast64bit(size_t v) {
-      return _mm512_set1_epi64(v);
-    }
-
-    static __forceinline size_t extract64bit(const vuint16& v)
-    {
-      return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
-    }
-
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
     /// Array Access
     /// Array Access
     ////////////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////
@@ -315,18 +300,6 @@ namespace embree
     return _mm512_mask_or_epi32(f,m,t,t); 
     return _mm512_mask_or_epi32(f,m,t,t); 
   }
   }
 
 
-  __forceinline void xchg(const vboolf16& m, vuint16& a, vuint16& b) {
-    const vuint16 c = a; a = select(m,b,a); b = select(m,c,b);
-  }
-
-  __forceinline vboolf16 test(const vboolf16& m, const vuint16& a, const vuint16& b) {
-    return _mm512_mask_test_epi32_mask(m,a,b);
-  }
-
-  __forceinline vboolf16 test(const vuint16& a, const vuint16& b) {
-    return _mm512_test_epi32_mask(a,b);
-  }
-
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Movement/Shifting/Shuffling Functions
   // Movement/Shifting/Shuffling Functions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -441,3 +414,11 @@ namespace embree
     return cout;
     return cout;
   }
   }
 }
 }
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

+ 38 - 111
thirdparty/embree-aarch64/common/simd/vuint4_sse2.h → thirdparty/embree/common/simd/vuint4_sse2.h

@@ -1,10 +1,18 @@
-// Copyright 2009-2020 Intel Corporation
+// Copyright 2009-2021 Intel Corporation
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 #pragma once
 #pragma once
 
 
 #include "../math/math.h"
 #include "../math/math.h"
 
 
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
 namespace embree
 namespace embree
 {
 {
   /* 4-wide SSE integer type */
   /* 4-wide SSE integer type */
@@ -87,64 +95,27 @@ namespace embree
     static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& i) { storeu(ptr,select(mask,i,loadu(ptr))); }
     static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& i) { storeu(ptr,select(mask,i,loadu(ptr))); }
 #endif
 #endif
 
 
-#if defined(__aarch64__)
-    static __forceinline vuint4 load(const uint8_t* ptr) {
-        return _mm_load4epu8_epi32(((__m128i*)ptr));
-    }
-    static __forceinline vuint4 loadu(const uint8_t* ptr) {
-        return _mm_load4epu8_epi32(((__m128i*)ptr));
-    }
-#elif defined(__SSE4_1__)
-    static __forceinline vuint4 load(const uint8_t* ptr) {
+#if defined(__SSE4_1__)
+    static __forceinline vuint4 load(const unsigned char* ptr) {
       return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
       return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
     }
     }
 
 
-    static __forceinline vuint4 loadu(const uint8_t* ptr) {
+    static __forceinline vuint4 loadu(const unsigned char* ptr) {
       return  _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
       return  _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
     }
     }
 
 
 #endif
 #endif
 
 
     static __forceinline vuint4 load(const unsigned short* ptr) {
     static __forceinline vuint4 load(const unsigned short* ptr) {
-#if defined(__aarch64__)
-      return _mm_load4epu16_epi32(((__m128i*)ptr));
-#elif defined (__SSE4_1__)
+#if defined (__SSE4_1__)
       return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
       return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
 #else
 #else
       return vuint4(ptr[0],ptr[1],ptr[2],ptr[3]);
       return vuint4(ptr[0],ptr[1],ptr[2],ptr[3]);
 #endif
 #endif
     } 
     } 
 
 
-    static __forceinline void store_uint8(uint8_t* ptr, const vuint4& v) {
-#if defined(__aarch64__) 
-        uint32x4_t x = uint32x4_t(v.v);
-        uint16x4_t y = vqmovn_u32(x);
-        uint8x8_t z = vqmovn_u16(vcombine_u16(y, y));
-        vst1_lane_u32((uint32_t *)ptr, uint32x2_t(z), 0);
-#elif defined(__SSE4_1__)
-      __m128i x = v;
-      x = _mm_packus_epi32(x, x);
-      x = _mm_packus_epi16(x, x);
-      *(unsigned*)ptr = _mm_cvtsi128_si32(x);
-#else
-      for (size_t i=0;i<4;i++)
-        ptr[i] = (uint8_t)v[i];
-#endif
-    }
-
-    static __forceinline void store_uint8(unsigned short* ptr, const vuint4& v) {
-#if defined(__aarch64__)
-        uint32x4_t x = (uint32x4_t)v.v;
-        uint16x4_t y = vqmovn_u32(x);
-        vst1_u16(ptr, y);
-#else
-      for (size_t i=0;i<4;i++)
-        ptr[i] = (unsigned short)v[i];
-#endif
-    }
-
     static __forceinline vuint4 load_nt(void* ptr) {
     static __forceinline vuint4 load_nt(void* ptr) {
-#if (defined(__aarch64__)) || defined(__SSE4_1__)
+#if defined(__SSE4_1__)
       return _mm_stream_load_si128((__m128i*)ptr); 
       return _mm_stream_load_si128((__m128i*)ptr); 
 #else
 #else
       return _mm_load_si128((__m128i*)ptr); 
       return _mm_load_si128((__m128i*)ptr); 
@@ -152,8 +123,8 @@ namespace embree
     }
     }
     
     
     static __forceinline void store_nt(void* ptr, const vuint4& v) {
     static __forceinline void store_nt(void* ptr, const vuint4& v) {
-#if !defined(__aarch64__) && defined(__SSE4_1__)
-      _mm_stream_ps((float*)ptr, _mm_castsi128_ps(v)); 
+#if defined(__SSE4_1__)
+      _mm_stream_ps((float*)ptr,_mm_castsi128_ps(v)); 
 #else
 #else
       _mm_store_si128((__m128i*)ptr,v);
       _mm_store_si128((__m128i*)ptr,v);
 #endif
 #endif
@@ -161,14 +132,14 @@ namespace embree
 
 
     template<int scale = 4>
     template<int scale = 4>
     static __forceinline vuint4 gather(const unsigned int* ptr, const vint4& index) {
     static __forceinline vuint4 gather(const unsigned int* ptr, const vint4& index) {
-#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__AVX2__)
       return _mm_i32gather_epi32((const int*)ptr, index, scale);
       return _mm_i32gather_epi32((const int*)ptr, index, scale);
 #else
 #else
       return vuint4(
       return vuint4(
-          *(unsigned int*)(((int8_t*)ptr)+scale*index[0]),
-          *(unsigned int*)(((int8_t*)ptr)+scale*index[1]),
-          *(unsigned int*)(((int8_t*)ptr)+scale*index[2]),
-          *(unsigned int*)(((int8_t*)ptr)+scale*index[3]));
+          *(unsigned int*)(((char*)ptr)+scale*index[0]),
+          *(unsigned int*)(((char*)ptr)+scale*index[1]),
+          *(unsigned int*)(((char*)ptr)+scale*index[2]),
+          *(unsigned int*)(((char*)ptr)+scale*index[3]));
 #endif
 #endif
     }
     }
 
 
@@ -177,13 +148,13 @@ namespace embree
       vuint4 r = zero;
       vuint4 r = zero;
 #if defined(__AVX512VL__)
 #if defined(__AVX512VL__)
       return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
       return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
-#elif defined(__AVX2__) && !defined(__aarch64__)
+#elif defined(__AVX2__)
       return _mm_mask_i32gather_epi32(r, (const int*)ptr, index, mask, scale);
       return _mm_mask_i32gather_epi32(r, (const int*)ptr, index, mask, scale);
 #else
 #else
-      if (likely(mask[0])) r[0] = *(unsigned int*)(((int8_t*)ptr)+scale*index[0]);
-      if (likely(mask[1])) r[1] = *(unsigned int*)(((int8_t*)ptr)+scale*index[1]);
-      if (likely(mask[2])) r[2] = *(unsigned int*)(((int8_t*)ptr)+scale*index[2]);
-      if (likely(mask[3])) r[3] = *(unsigned int*)(((int8_t*)ptr)+scale*index[3]);
+      if (likely(mask[0])) r[0] = *(unsigned int*)(((char*)ptr)+scale*index[0]);
+      if (likely(mask[1])) r[1] = *(unsigned int*)(((char*)ptr)+scale*index[1]);
+      if (likely(mask[2])) r[2] = *(unsigned int*)(((char*)ptr)+scale*index[2]);
+      if (likely(mask[3])) r[3] = *(unsigned int*)(((char*)ptr)+scale*index[3]);
       return r;
       return r;
 #endif
 #endif
     }
     }
@@ -373,25 +344,16 @@ namespace embree
   __forceinline vuint4 unpacklo(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
   __forceinline vuint4 unpacklo(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
   __forceinline vuint4 unpackhi(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
   __forceinline vuint4 unpackhi(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
 
 
-#if defined(__aarch64__)
-  template<int i0, int i1, int i2, int i3>
-  __forceinline vuint4 shuffle(const vuint4& v) {
-    return vreinterpretq_s32_u8(vqtbl1q_u8( (uint8x16_t)v.v, _MN_SHUFFLE(i0, i1, i2, i3)));
-  }
-  template<int i0, int i1, int i2, int i3>
-  __forceinline vuint4 shuffle(const vuint4& a, const vuint4& b) {
-    return vreinterpretq_s32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
-  }
-#else
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
   __forceinline vuint4 shuffle(const vuint4& v) {
   __forceinline vuint4 shuffle(const vuint4& v) {
     return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
     return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
   }
   }
+
   template<int i0, int i1, int i2, int i3>
   template<int i0, int i1, int i2, int i3>
   __forceinline vuint4 shuffle(const vuint4& a, const vuint4& b) {
   __forceinline vuint4 shuffle(const vuint4& a, const vuint4& b) {
     return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
     return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
   }
   }
-#endif
+
 #if defined(__SSE3__)
 #if defined(__SSE3__)
   template<> __forceinline vuint4 shuffle<0, 0, 2, 2>(const vuint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
   template<> __forceinline vuint4 shuffle<0, 0, 2, 2>(const vuint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
   template<> __forceinline vuint4 shuffle<1, 1, 3, 3>(const vuint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
   template<> __forceinline vuint4 shuffle<1, 1, 3, 3>(const vuint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
@@ -403,10 +365,7 @@ namespace embree
     return shuffle<i,i,i,i>(v);
     return shuffle<i,i,i,i>(v);
   }
   }
 
 
-#if defined(__aarch64__)
-  template<int src> __forceinline unsigned int extract(const vuint4& b);
-  template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b);
-#elif defined(__SSE4_1__)
+#if defined(__SSE4_1__)
   template<int src> __forceinline unsigned int extract(const vuint4& b) { return _mm_extract_epi32(b, src); }
   template<int src> __forceinline unsigned int extract(const vuint4& b) { return _mm_extract_epi32(b, src); }
   template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { return _mm_insert_epi32(a, b, dst); }
   template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { return _mm_insert_epi32(a, b, dst); }
 #else
 #else
@@ -414,50 +373,11 @@ namespace embree
   template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { vuint4 c = a; c[dst&3] = b; return c; }
   template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { vuint4 c = a; c[dst&3] = b; return c; }
 #endif
 #endif
 
 
-#if defined(__aarch64__)
-  template<> __forceinline unsigned int extract<0>(const vuint4& b) {
-    return b[0];
-  }
-  template<> __forceinline unsigned int extract<1>(const vuint4& b) {
-    return b[1];
-  }
-  template<> __forceinline unsigned int extract<2>(const vuint4& b) {
-    return b[2];
-  }
-  template<> __forceinline unsigned int extract<3>(const vuint4& b) {
-    return b[3];
-  }
-                                                                               
-  template<> __forceinline vuint4 insert<0>(const vuint4& a, unsigned b){
-    vuint4 c = a;
-    c[0] = b;
-    return c;
-  }
-  template<> __forceinline vuint4 insert<1>(const vuint4& a, unsigned b){
-    vuint4 c = a;
-    c[1] = b;
-    return c;
-  }
-  template<> __forceinline vuint4 insert<2>(const vuint4& a, unsigned b){
-    vuint4 c = a;
-    c[2] = b;
-    return c;
-  }
-  template<> __forceinline vuint4 insert<3>(const vuint4& a, unsigned b){
-    vuint4 c = a;
-    c[3] = b;
-    return c;
-  }
-                                                                               
-  __forceinline unsigned int toScalar(const vuint4& v) {
-    return v[0];
-  }
-#else
+
   template<> __forceinline unsigned int extract<0>(const vuint4& b) { return _mm_cvtsi128_si32(b); }
   template<> __forceinline unsigned int extract<0>(const vuint4& b) { return _mm_cvtsi128_si32(b); }
 
 
   __forceinline unsigned int toScalar(const vuint4& v) { return _mm_cvtsi128_si32(v); }
   __forceinline unsigned int toScalar(const vuint4& v) { return _mm_cvtsi128_si32(v); }
-#endif
-                                                                               
+
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   /// Reductions
   /// Reductions
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
@@ -497,3 +417,10 @@ namespace embree
   }
   }
 }
 }
 
 
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble

Some files were not shown because too many files changed in this diff